Você estava muito perto, mas é claro
$eq
apenas retorna um true/false
valor, então para tornar esse numérico você precisa 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 ]
}
}
}}
])
Como operador "ternário"
$cond
pega uma condição lógica como seu primeiro argumento (if) e então retorna o segundo argumento onde a avaliação é true
(então) ou o terceiro argumento onde false
(senão). Isso torna true/false
retorna em 1
e 0
para alimentar $sum
respectivamente. Observe também que "case" é sensível para
$eq
. Se você tiver maiúsculas e minúsculas, provavelmente desejará $toLower
nas expressões: "$cond": [ { "$eq": [ { "$toLower": "$rating" }, "bad" ] }, 1, 0 ]
Em uma nota um pouco diferente, a seguinte agregação geralmente é mais flexível para diferentes valores possíveis e executa anéis em torno das somas condicionais em termos de desempenho:
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"
}
}
}}
])
Em vez disso, isso daria uma saída como esta:
{
"_id": "item_1"
"results":[
{ "rating": "good", "count": 12 },
{ "rating": "neutral", "count": 10 }
{ "rating": "bad", "count": 67 }
]
}
São todas as mesmas informações, mas você não precisou corresponder explicitamente aos valores e é executado muito mais rápido dessa maneira.