Je was heel dichtbij, maar natuurlijk $eq
retourneert gewoon een true/false
waarde, dus om die numerieke waarde te maken heb je $cond
. nodig :
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 ]
}
}
}}
])
Als een "ternaire" operator $cond
neemt een logische voorwaarde als eerste argument (if) en retourneert vervolgens het tweede argument waarbij de evaluatie true
is (then) of het derde argument waarbij false
(anders). Dit maakt true/false
keert terug naar 1
en 0
om door te geven aan $sum
respectievelijk.
Merk ook op dat "case" gevoelig is voor $eq
. Als je verschillende hoofdletters hebt, wil je waarschijnlijk $toLower
in de uitdrukkingen:
"$cond": [ { "$eq": [ { "$toLower": "$rating" }, "bad" ] }, 1, 0 ]
Met een iets andere opmerking, de volgende aggregatie is meestal flexibeler voor verschillende mogelijke waarden en draait rond de voorwaardelijke sommen in termen van prestaties:
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"
}
}
}}
])
Dat zou in plaats daarvan de volgende output opleveren:
{
"_id": "item_1"
"results":[
{ "rating": "good", "count": 12 },
{ "rating": "neutral", "count": 10 }
{ "rating": "bad", "count": 67 }
]
}
Het is allemaal dezelfde informatie, maar je hoefde de waarden niet expliciet te matchen en het wordt op deze manier veel sneller uitgevoerd.