I have an javascript array and it contains another array of objects. Now I want to do sum of the field of objects having same symbol key. How to do that ?
The array I have
let orders = [
{
"_id": "6c18cea3-7d37-4f85-b369-abf03e7ff873",
"subOrders": [
{
"symbol": "SUZ",
"fulfilledQty": "49.333991119"
},
{
"symbol": "FSLR",
"fulfilledQty": "2.895864705"
}
]
},
{
"_id": "acf75fcb-496a-4825-b7bc-cef60556fe49",
"subOrders": [
{
"symbol": "FSLR",
"fulfilledQty": "1"
},
{
"symbol": "SUZ",
"fulfilledQty": "1"
}
]
},
{
"_id": "e32041a1-17f0-44c4-9fc4-4619e0507392",
"subOrders": [
{
"symbol": "SUZ",
"fulfilledQty": "8.751458576"
},
{
"symbol": "FSLR",
"fulfilledQty": "0.587774294"
}
]
}
]
The array I want from above array
[
{
"symbol": "FSLR",
"fulfilledQty": "4.483638999"
},
{
"symbol": "SUZ",
"fulfilledQty": "59.085449695"
}
]
So I want to the sum of fulfilledQty
of same symbol
I tried this
let totalOrder = {};
for(let order of orders){
for(subOrder of order.subOrders){
totalOrder[subOrder.symbol] = totalOrder[subOrder.symbol] ?
parseFloat(totalOrder[subOrder.symbol])
parseFloat(subOrder.fulfilledQty) :
parseFloat(subOrder.fulfilledQty);
}
}
That gives me this object
{SUZ: "59.085449695", FSLR: "4.483638999"}
then I will convert it to array. Because Inside inner for loop I will have to put another loop to compare the symbols So this will not iterate each time to compare symbols That can be achieved using the loops but do so I will have to iterate the arrays too many times Is there any simpler way to do so ?
CodePudding user response:
You can use a .reduce()
to sum up the qty by symbol, then map that into the desired array:
const input = [
{
"_id": "6c18cea3-7d37-4f85-b369-abf03e7ff873",
"subOrders": [
{ "symbol": "SUZ", "fulfilledQty": "49.333991119" },
{ "symbol": "FSLR", "fulfilledQty": "2.895864705" }
]
},
{
"_id": "acf75fcb-496a-4825-b7bc-cef60556fe49",
"subOrders": [
{ "symbol": "FSLR", "fulfilledQty": "1" },
{ "symbol": "SUZ", "fulfilledQty": "1" }
]
},
{
"_id": "e32041a1-17f0-44c4-9fc4-4619e0507392",
"subOrders": [
{ "symbol": "SUZ", "fulfilledQty": "8.751458576" },
{ "symbol": "FSLR", "fulfilledQty": "0.587774294" }
]
}
];
let sums = input.reduce((acc, obj) => {
obj.subOrders.forEach(item => {
let symbol = item.symbol;
let qty = Number(item.fulfilledQty);
if(!acc[symbol]) {
acc[symbol] = qty;
} else {
acc[symbol] = qty;
}
});
return acc;
}, {});
let result = Object.keys(sums).sort().map(symbol => {
return {
symbol: symbol,
fulfilledQty: sums[symbol].toString()
};
});
console.log(result);
CodePudding user response:
As you have mentioned you are getting the array from mongodb then you can make a aggregation pipeline.
let aggregation = [
{
'$match': {
//Your query here
}
}, {
'$unwind': {
'path': '$subOrders'
}
}, {
'$group': {
'_id': '$symbol',
'symbol': {'$first': "$symbol"},
'total': {
'$sum': {
'$toDouble': '$fulfilledQty'
}
}
}
}
]
CodePudding user response:
We can use Array.flatMap()
and Array.reduce()
to do it
let result = orders.flatMap(e => e.subOrders).reduce((a,{symbol,fulfilledQty}) => {
a[symbol] = a[symbol]??0
a[symbol] = fulfilledQty
return a
},{})
console.log(result)
let orders = [
{
"_id": "6c18cea3-7d37-4f85-b369-abf03e7ff873",
"subOrders": [
{
"symbol": "SUZ",
"fulfilledQty": "49.333991119"
},
{
"symbol": "FSLR",
"fulfilledQty": "2.895864705"
}
]
},
{
"_id": "acf75fcb-496a-4825-b7bc-cef60556fe49",
"subOrders": [
{
"symbol": "FSLR",
"fulfilledQty": "1"
},
{
"symbol": "SUZ",
"fulfilledQty": "1"
}
]
},
{
"_id": "e32041a1-17f0-44c4-9fc4-4619e0507392",
"subOrders": [
{
"symbol": "SUZ",
"fulfilledQty": "8.751458576"
},
{
"symbol": "FSLR",
"fulfilledQty": "0.587774294"
}
]
}
]
let result = orders.flatMap(e => e.subOrders).reduce((a,{symbol,fulfilledQty}) => {
a[symbol] = a[symbol]??0
a[symbol] = fulfilledQty
return a
},{})
console.log(result)