For example, I have something in my database like in customers collection.
{
Max: {
shoping_list: {
food: { Pizza: 2, Ramen: 1, Sushi: 5 }
}
},
John: {
shoping_list: {
food: { Pizza: 2, Ramen: 1, Burger: 1 }
}
}
}
In my backend, I want to get the sum of food
const request = await customers.aggregate([
{
$group: {
_id: null,
Pizza: {
$sum: '$shoping_list.food.Pizza',
},
Is there a way how to update or get the sum automatically without manually writing every food from the shopping_list?
CodePudding user response:
The design of the document may lead the query looks complex but still achievable.
$replaceRoot- Replace the input document with a new document.1.1.
$reduce- Iterate the array and transform it into a new form (array).1.2.
input- Transform key-value pair of current document$$ROOTto an array of objects such as:[{ k: "", v: "" }]1.3.
initialValue- Initialize the value with an empty array. And this will result in the output in the array.1.4.
in1.4.1.
$concatArrays- Combine aggregate array result ($$value) with 1.4.2.1.4.2. With the
$condoperator to filter out the document with{ k: "_id" }, and we transform the current iterate object'svshoping_list.foodto the array via$objectToArray.$unwind- Deconstruct thefoodsarray into multiple documents.$group- Group byfoods.kand perform sum forfoods.v.
db.collection.aggregate([
{
$replaceRoot: {
newRoot: {
foods: {
$reduce: {
input: {
$objectToArray: "$$ROOT"
},
initialValue: [],
in: {
$concatArrays: [
"$$value",
{
$cond: {
if: {
$ne: [
"$$this.k",
"_id"
]
},
then: {
$objectToArray: "$$this.v.shoping_list.food"
},
else: []
}
}
]
}
}
}
}
}
},
{
$unwind: "$foods"
},
{
$group: {
_id: "$foods.k",
sum: {
$sum: "$foods.v"
}
}
}
])
