A maneira mais "funcional" de fazer isso é pular o
$unwind
completamente e simplesmente $group
contar. Essencialmente, matrizes de "filtro" obtêm o $size
dos resultados para $sum
:db.objects.aggregate([
{ "$match": {
"createddate": {
"$gte": ISODate("2015-08-30T00:00:00.000Z")
},
"activity.action": "test_action"
}},
{ "$group": {
"_id": null,
"count": {
"$sum": {
"$size": {
"$setDifference": [
{ "$map": {
"input": "$activity",
"as": "el",
"in": {
"$cond": [
{ "$eq": [ "$$el.action", "test_action" ] },
"$$el",
false
]
}
}},
[false]
]
}
}
}
}}
])
Versões futuras do MongoDB terão
$filter
, o que torna isso muito mais simples:db.objects.aggregate([
{ "$match": {
"createddate": {
"$gte": ISODate("2015-08-30T00:00:00.000Z")
},
"activity.action": "test_action"
}},
{ "$group": {
"_id": null,
"count": {
"$sum": {
"$size": {
"$filter": {
"input": "$activity",
"as": "el",
"cond": {
"$eq": [ "$$el.action", "test_action" ]
}
}
}
}
}
}}
])
Usando
$unwind
faz com que os documentos sejam desnormalizados e cria efetivamente uma cópia por entrada de matriz. Sempre que possível, você deve evitar isso devido ao custo muitas vezes extremo. Filtrar e contar entradas de matriz por documento é muito mais rápido em comparação. Assim como um simples $match
e $group
pipeline em comparação com muitos estágios.