Du var väldigt nära, men naturligtvis $eq
returnerar bara en true/false
värde, så för att göra det numeriska behöver du $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 ]
}
}
}}
])
Som en "ternär" operator $cond
tar ett logiskt villkor som det första argumentet (om) och returnerar sedan det andra argumentet där utvärderingen är true
(då) eller det tredje argumentet där false
(annan). Detta gör true/false
återgår till 1
och 0
att mata till $sum
respektive.
Observera också att "case" är känsligt för $eq
. Om du har olika skiftlägen vill du förmodligen ha $toLower
i uttrycken:
"$cond": [ { "$eq": [ { "$toLower": "$rating" }, "bad" ] }, 1, 0 ]
På en något annorlunda notering är följande aggregering vanligtvis mer flexibel för olika möjliga värden och kör ringar runt de villkorade summorna när det gäller prestanda:
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"
}
}
}}
])
Det skulle istället ge utdata så här:
{
"_id": "item_1"
"results":[
{ "rating": "good", "count": 12 },
{ "rating": "neutral", "count": 10 }
{ "rating": "bad", "count": 67 }
]
}
Det är samma information, men du behövde inte uttryckligen matcha värdena och det körs mycket snabbare på detta sätt.