I have a MongoDB collection named Venue
with elements of type:
{
venue: "Grand Hall",
sections: [{
name: "Lobby",
drinks: [{
name: "Vodka",
quantity: 3
}, {
name: "Red Wine",
quantity: 1
}]
}, {
name: "Ballroom",
drinks: [{
name: "Vodka",
quantity: 22
}, {
name: "Red Wine",
quantity: 50
}]
}]
}
I want to calculate the total amounts of each drink for the party. So I want my result to be something like that:
{
venue: "Grand Hall",
sections: 2,
drinks: [{
name: "Vodka",
quantity: 25
}, {
name: "Red Wine",
quantity: 51
}]
}
There are lots of ways to do this. Here's another one using "$reduce"
and "$map"
, etc.
db.Venue.aggregate({
"$match": {
"venue": "Grand Hall"
}
},
{
"$set": {
"sections": {"$size": "$sections"},
"drinks": {
"$reduce": {
"input": { // flatten array of drink objects
"$reduce": {
"input": "$sections.drinks",
"initialValue": [],
"in": {"$concatArrays": ["$$value", "$$this"]}
}
},
"initialValue": [],
"in": {
"$let": {
"vars": { // position of drink in $$value, or -1 if not found
"idx": {"$indexOfArray": ["$$value.name", "$$this.name"]}
},
"in": {
"$cond": [
{"$eq": ["$$idx", -1]}, // not found?
{"$concatArrays": ["$$value", ["$$this"]]}, // not found, add object
{ // found, so update object in $$value by summing quantities
"$map": {
"input": "$$value",
"as": "val",
"in": {
"$cond": [
{"$eq": ["$$val.name", "$$this.name"]}, // right object?
{ // yes, update quantity
"name": "$$val.name",
"quantity": {"$sum": ["$$val.quantity", "$$this.quantity"]}
},
"$$val" // wrong object for update, so just keep it
]
}
}
}
]
}
}
}
}
}
}
})
Try it on mongoplayground.net.