Vous étiez très proche, mais bien sûr $eq
renvoie juste un true/false
valeur, donc pour rendre ce numérique, vous avez besoin de $cond
:
db.collection(collectionName).aggregate([
{ "$group" : {
"_id": "$item",
"good_count": {
"$sum": {
"$cond": [ { "$eq": [ "$rating", "good" ] }, 1, 0]
}
},
"neutral_count":{
"$sum": {
"$cond": [ { "$eq": [ "$rating", "neutral" ] }, 1, 0 ]
}
},
"bad_count": {
"$sum": {
"$cond": [ { "$eq": [ "$rating", "bad" ] }, 1, 0 ]
}
}
}}
])
En tant qu'opérateur "ternaire" $cond
prend une condition logique comme premier argument (if) puis renvoie le deuxième argument où l'évaluation est true
(alors) ou le troisième argument où false
(autre). Cela rend true/false
retourne en 1
et 0
pour alimenter $sum
respectivement.
Notez également que la "casse" est sensible pour $eq
. Si vous avez des cas variables, vous voudrez probablement $toLower
dans les expressions :
"$cond": [ { "$eq": [ { "$toLower": "$rating" }, "bad" ] }, 1, 0 ]
Sur une note légèrement différente, l'agrégation suivante est généralement plus flexible pour différentes valeurs possibles et tourne autour des sommes conditionnelles en termes de performances :
db.collection(collectionName).aggregate([
{ "$group": {
"_id": {
"item": "$item",
"rating": { "$toLower": "$rating" }
},
"count": { "$sum": 1 }
}},
{ "$group": {
"_id": "$_id.item",
"results": {
"$push": {
"rating": "$_id.rating",
"count": "$count"
}
}
}}
])
Cela donnerait plutôt une sortie comme celle-ci :
{
"_id": "item_1"
"results":[
{ "rating": "good", "count": 12 },
{ "rating": "neutral", "count": 10 }
{ "rating": "bad", "count": 67 }
]
}
Ce sont toutes les mêmes informations, mais vous n'avez pas eu à faire correspondre explicitement les valeurs et cela s'exécute beaucoup plus rapidement de cette façon.