Hello
Reduce read the array and sums
Filter read the array 2 times,one sum the up the other sums the downs
Unwind the votes,replace each document with {up 1} or {down 1} depend on what it voted.
Group and sum.
I think the easier is the filter,just reads the array 2 times(reduce reads it 1 time)
I think it does what you want.
db.collection.aggregate([
{
"$project": {
"_id": 0,
"upDown": {
"$reduce": {
"input": "$votes",
"initialValue": [
0,
0
],
"in": {
"$let": {
"vars": {
"votes": "$$value",
"vote": "$$this"
},
"in": {
"$cond": [
{
"$eq": [
"$$vote.action",
"up"
]
},
[
{
"$add": [
{
"$arrayElemAt": [
"$$votes",
0
]
},
1
]
},
{
"$arrayElemAt": [
"$$votes",
1
]
}
],
[
{
"$arrayElemAt": [
"$$votes",
0
]
},
{
"$add": [
{
"$arrayElemAt": [
"$$votes",
1
]
},
1
]
}
]
]
}
}
}
}
}
}
},
{
"$project": {
"up": {
"$arrayElemAt": [
"$upDown",
0
]
},
"down": {
"$arrayElemAt": [
"$upDown",
1
]
}
}
}
])
db.collection.aggregate([
{
"$project": {
"_id": 0,
"up": {
"$size": {
"$filter": {
"input": "$votes",
"as": "vote",
"cond": {
"$eq": [
"$$vote.action",
"up"
]
}
}
}
},
"down": {
"$size": {
"$filter": {
"input": "$votes",
"as": "vote",
"cond": {
"$eq": [
"$$vote.action",
"down"
]
}
}
}
}
}
}
])
db.collection.aggregate([
{
"$unwind": {
"path": "$votes"
}
},
{
"$replaceRoot": {
"newRoot": {
"$cond": [
{
"$eq": [
"$votes.action",
"up"
]
},
{
"up": 1
},
{
"down": 1
}
]
}
}
},
{
"$group": {
"_id": null,
"up": {
"$sum": "$up"
},
"down": {
"$sum": "$down"
}
}
},
{
"$project": {
"_id": 0
}
}
])