-2

I currently have an array of objects that looks like this:

const orders = [
  { id: '1', userId: '3', total: 300 },
  { id: '2', userId: '4', total: 200 },
  { id: '3', userId: '5', total: 101 },
  { id: '4', userId: '6', total: 80 },
  { id: '5', userId: '7', total: 76 },
  { id: '6', userId: '8', total: 44 },
  { id: '7', userId: '9', total: 1000 },
  { id: '8', userId: '10', total: 99 },
  { id: '9', userId: '3', total: 65 },
  { id: '10', userId: '4', total: 22 }
];

How would I combine the totals for any object in the array that shares the same userId?

I would like my outcome to look like this:

const newOrdersArray = [
  { id: '1', userId: '3', total: 365 },
  { id: '2', userId: '4', total: 222 },
  { id: '3', userId: '5', total: 101 },
  { id: '4', userId: '6', total: 80 },
  { id: '5', userId: '7', total: 76 },
  { id: '6', userId: '8', total: 44 },
  { id: '7', userId: '9', total: 1000 },
  { id: '8', userId: '10', total: 99 }
];
Keaton S
  • 22
  • 4
  • 1
    What have you attempted? – Kinglish Dec 01 '21 at 21:04
  • I have tried to filter out objects with the same userId combine their totals and then add back to the filtered array. However, I have not had any luck and do not think this is correct. – Keaton S Dec 01 '21 at 21:24
  • Theres a number of ways you can do this, you can iterate the array, destructure and make a copy, and so on. But in principle you should access the object that you want to modify like so. orders[0].total += 65 Be aware that array indexes start at 0, i would change the ids to start at 0 aswell for better reading. – Luca De Acha Dec 01 '21 at 21:24
  • Presumably `id` should *not* be in the output elements. – jarmod Dec 01 '21 at 21:25
  • Does this answer your question? [Group objects by multiple properties in array then sum up their values](https://stackoverflow.com/questions/46794232/group-objects-by-multiple-properties-in-array-then-sum-up-their-values) – pilchard Dec 01 '21 at 21:38
  • or [How to group by and sum an array of objects?](https://stackoverflow.com/questions/29364262/how-to-group-by-and-sum-an-array-of-objects) or [Most efficient method to groupby on an array of objects](https://stackoverflow.com/questions/14446511/most-efficient-method-to-groupby-on-an-array-of-objects) – pilchard Dec 01 '21 at 21:40

5 Answers5

1

Here's a way using reduce

const orders = [
  { id: '1', userId: '3', total: 300 },
  { id: '2', userId: '4', total: 200 },
  { id: '3', userId: '5', total: 101 },
  { id: '4', userId: '6', total: 80 },
  { id: '5', userId: '7', total: 76 },
  { id: '6', userId: '8', total: 44 },
  { id: '7', userId: '9', total: 1000 },
  { id: '8', userId: '10', total: 99 },
  { id: '9', userId: '3', total: 65 },
  { id: '10', userId: '4', total: 22 }
];

let combined = orders.reduce((b, a) => {
  let index = b.findIndex(arr => arr.userId == a.userId);
  delete a.id
  if (index > -1) b[index].total += a.total;
  else b.push(a);
  return b;
}, [])

console.log(combined);
Kinglish
  • 23,358
  • 3
  • 22
  • 43
1

Try this:

const orders = [
  { id: '1', userId: '3', total: 300 },
  { id: '2', userId: '4', total: 200 },
  { id: '3', userId: '5', total: 101 },
  { id: '4', userId: '6', total: 80 },
  { id: '5', userId: '7', total: 76 },
  { id: '6', userId: '8', total: 44 },
  { id: '7', userId: '9', total: 1000 },
  { id: '8', userId: '10', total: 99 },
  { id: '9', userId: '3', total: 65 },
  { id: '10', userId: '4', total: 22 }
];

const totals = [];
orders.forEach(x => {
  const obj = totals.find(o => o.userId === x.userId);
  if (obj) {
    obj.total = obj.total + x.total;
  } else {
    totals.push(x);
  }
});

console.log(totals);
kapantzak
  • 11,610
  • 4
  • 39
  • 61
1

Here is a variation of the .reduce() approach in which the IDs are collected in arrays for each userID:

const orders = [
  { id: '1', userId: '3', total: 300 },
  { id: '2', userId: '4', total: 200 },
  { id: '3', userId: '5', total: 101 },
  { id: '4', userId: '6', total: 80 },
  { id: '5', userId: '7', total: 76 },
  { id: '6', userId: '8', total: 44 },
  { id: '7', userId: '9', total: 1000 },
  { id: '8', userId: '10', total: 99 },
  { id: '9', userId: '3', total: 65 },
  { id: '10', userId: '4', total: 22 }
];

let combined = Object.values(orders.reduce((a,c) => { 
  let e = (a[c.userId] = a[c.userId] || {ids:[],userId:c.userId,total:0});
  e.total+=c.total;
  e.ids.push(c.id);
  return a;
}, {}))

console.log(combined);
Carsten Massmann
  • 26,510
  • 2
  • 22
  • 43
0

I don't know the use case behind this, but looking at the data, I assume that the id is the id of the specific order. It feels somehow odd to keep this in the cumulated result, where the total is only in relation to all orders of the user and not any longer to one single order. Therefore I would just drop this and calculate the total like this:

totals = orders.reduce((totals, order) => {
  totals[order.userId] = (totals[order.userId] ?? 0) + order.total;
  return totals;
}, {});

Yes, you don't have an array any longer but an object with the userIds as key instead. If this does not fit your specific use case, simply transform it again.

PatrickD
  • 1,136
  • 5
  • 7
0

You could take an object for addressing same userId and get the values from the object as result.

const
    orders = [{ id: '1', userId: '3', total: 300 }, { id: '2', userId: '4', total: 200 }, { id: '3', userId: '5', total: 101 }, { id: '4', userId: '6', total: 80 }, { id: '5', userId: '7', total: 76 }, { id: '6', userId: '8', total: 44 }, { id: '7', userId: '9', total: 1000 }, { id: '8', userId: '10', total: 99 }, { id: '9', userId: '3', total: 65 }, { id: '10', userId: '4', total: 22 }],
    result = Object.values(orders.reduce((r, o) => {
        r[o.userId] ??= { ...o, total: 0 };
        r[o.userId].total += o.total;
        return r;
    }, {}));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392