I have a collection that looks like:
{
"_id" : ObjectId("58b77d1349b2e11c06d9cb8a"),
"blocks" : [
{
"userId" : ObjectId("5893a9a64ce29f0231bd060c"),
"_id" : ObjectId("58b786c5665532d53c21ac72"),
}
]
}
{
"_id" : ObjectId("58b77d1349b2e11c06d9cb8c"),
"blocks" : [
{
"userId" : ObjectId("581bbb0422e3911e24ea0276"),
"_id" : ObjectId("592f2d8f092b3b6e374d9bec"),
}
],
}
{
"_id" : ObjectId("58b85e16894bf623065a0899"),
"blocks" : [
{
"userId" : ObjectId("56e086538146ecb412f974e9"),
"_id" : ObjectId("592f2cb506dc59992009424a"),
}
]
}
And I want to sum the number of elements in all "blocks" arrays in the collection, so I choose an aggregation query in the shell:
db.userblocks.aggregate([
{
$match: {
blocks: { $gt: [] }
}
},
{
$group: {
_id: null,
cntArray: {
$push: { $size: "$blocks" }
}
}
},
{
$project: {
"num_blocks": {
$reduce: {
input: "$cntArray",
initialValue: 0,
in: { $add: [ "$$value", "$$this" ] }
}
}
}
}
])
The problem is the aggregation query fails with an error:
Error: command failed: { "ok" : 0, "errmsg" : "invalid operator '$reduce'", "code" : 15999 } : aggregate failed
Looking at the documentation, what I'm doing seem valid, but I can't seem to figure what I've done wrong.
$reduceis available from 3.4. To check your server version, rundb.version()from shell. Btw, You don't need to use$reduce. Please refer to the linked duplicate.$groupshould be{ "$group": { "_id": null, "num_blocks": { "$sum": { "$size": $blocks" } } }}. That's it. Also your test for the array does not actually do what you think it does. Instead write{ "$match": { "blocks.0": { "$exists": true } } }. Which basically means if it has a0index, then in fact it is actually an array with something in it. The$gtexpression here is actually comparing the BSON types. Two stages and done.