Huuums
Huuums

Reputation: 107

Transform multiple arrays of objects into a single array while merging the objects on common key

So I have an array of objects that looks like this.

const myArray = [
  {
    values: [
      { date: "2018-11-02", "value1": 3, "value2": 5 },
      { date: "2018-11-01", "value1": 8, "value2": 9 },
      { date: "2018-10-31", "value1": 4, "value2": 10 },
    ],
    customer: "Customer One"
  },
  {
    values: [
      { date: "2018-11-02", "value1": 3 },
      { date: "2018-11-01", "value1": 5 },
      { date: "2018-10-31", "value1": 8 },
    ],
    customer: "Customer Two"
  }
];

All values of an object should be summed(by date) and then result as the value for the customer in the new object

What I want is it to look like this:

result = [
  { date: "2018-11-02", "Customer One": 8, "Customer Two": 3 },
  { date: "2018-11-01", "Customer One": 17, "Customer Two": 5 },
  { date: "2018-10-31", "Customer One": 14, "Customer Two": 8 },
]

I have working code for this but it feels way too complicated for what I need but I can't wrap my head around an easier way for some reason.

Here's my code (also on codesandbox: https://codesandbox.io/s/zvlpm167x):

const myArray = [
  {
    values: [
      { date: "2018-11-02", "value1": 3, "value2": 5 },
      { date: "2018-11-01", "value1": 8, "value2": 9 },
      { date: "2018-10-31", "value1": 4, "value2": 10 },
    ],
    customer: "Customer One"
  },
  {
    values: [
      { date: "2018-11-02", "value1": 3 },
      { date: "2018-11-01", "value1": 5 },
      { date: "2018-10-31", "value1": 8 },
    ],
    customer: "Customer Two"
  }
];

const flatArray = myArray.flat();

const sumObjectKeysExceptDate = object => Object.keys(object).reduce((sum, key) => {
  if (!Number.isNaN(parseInt(object[key], 10)) && key !== 'date') {
    return sum + parseInt(object[key], 10);
  }
  return sum;
}, 0);

const result = flatArray
  .reduce((acc, row) => [...acc, ...row.values.map(value => ({ [row.customer]: sumObjectKeysExceptDate(value), date: value.date }))], [])
  .reduce((acc, row) => {
    if (acc.find(innerrow => innerrow.date === row.date)) {
      return acc.map((innerrow) => {
        if (innerrow.date === row.date) {
          return { ...innerrow, ...row };
        }
        return innerrow;
      });
    }
    return [...acc, row];
  }, []);

console.log(result)

Upvotes: 1

Views: 129

Answers (1)

Nikhil Aggarwal
Nikhil Aggarwal

Reputation: 28445

Try following

  • Create an object with date as key and corresponding resulting object as value. And using Object.values get the final result
  • To build the object, use Array.reduce on outer array and for each value of inner array, check whether the entry for date exists or not in object. If it exists update it else create a new entry in object.
  • For each object in inner array, sum the values of all keys except date and set it in object corresponding to the customer name key.

const myArray = [{values: [{ date: "2018-11-02", "value1": 3, "value2": 5 },{ date: "2018-11-01", "value1": 8, "value2": 9 },{ date: "2018-10-31", "value1": 4, "value2": 10 },],customer: "Customer One"},{values: [{ date: "2018-11-02", "value1": 3 },{ date: "2018-11-01", "value1": 5 },{ date: "2018-10-31", "value1": 8 },],customer: "Customer Two"}];

let result = Object.values(myArray.reduce((a,c) => {
  c.values.forEach(({date, ...rest}) => {
    a[date] = a[date] || {date};
    a[date][c.customer] = Object.values(rest).reduce((d,e) => d + e);
  });
  return a;
}, {}));
console.log(result);

Upvotes: 1

Related Questions