Count values in array of objects

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.

1)Run Reduce

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
        ]
      }
    }
  }
])

2)Run Filter

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"
              ]
            }
          }
        }
      }
    }
  }
])

3)Run unwind and group

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
    }
  }
])
2 Likes