Using the MongoDB aggregation pipeline, is there a way to sum a value in an optional array field?
Suppose this collection:
db.myCollection.insert([
{_id: 1},
{ _id: 2,
events: [{_id: 201, value: 10}, {_id:202, value:20}]
}])
I would like to sum the events.value field using the aggregation pipeline, to produce this:
{_id: 1, totalValue: 0},
{_id: 2, totalValue: 30}
I can't use {$unwind: "$events"} because that would eliminate {_id: 1} from the output, so I tried to push the values to an array, and use $cond to create a single [0] if the element is missing:
db.myCollection.aggregate([
{$group: {_id:"$_id", values: {$push: "$events.value"}}},
{$project: {_id:1, values: {$cond: {
if: {$gt: [{$size: "$values"}, 0]},
then: "$values",
else: [[0]]
}}}} ])
This creates the following output:
{ "_id" : 2, "values" : [ [ 10, 20 ] ] }
{ "_id" : 1, "values" : [ [ 0 ] ] }
Now I can use $unwind on the values, but I am unable to sum the values.
Using $group with $sum
db.myCollection.aggregate([
{$group: {_id:"$_id", values: {$push: "$events.value"}}},
{$project: {_id:1, values: {$cond: {
if: {$gt: [{$size: "$values"}, 0]},
then: "$values",
else: [[0]]
}}}},
{$unwind: "$values"},
{$group: {_id:"$_id", totalValue: {$sum: "$values"}}} ])
produces this:
{ "_id" : 1, "totalValue" : 0 }
{ "_id" : 2, "totalValue" : 0 }
and using $project with $add produces an error:
db.myCollection.aggregate([
{$group: {_id:"$_id", values: {$push: "$events.value"}}},
{$project: {_id:1, values: {$cond: {
if: {$gt: [{$size: "$values"}, 0]},
then: "$values",
else: [[0]]
}}}},
{$project: {_id:1, totalValue: {$add: "$values"}}} ])
results in an exception:
exception: $add only supports numeric or date types, not Array