Geoff D
Geoff D

Reputation: 61

With MongoDB, how do I get the sum of array values... per array element in another array?

Here is a sample document...

    {
    "_id": ObjectId("61c7969702f8612e6b14db57"),
    "title": "Important Political Issue",
    "comments": [
        {
            "_id": ObjectId("61c796a349a42520e5c1eba4"),
            "comment": "This initiative should be passed",
            "votes": [
                {
                    "_id": ObjectId("61c797d7e7c81feb75c2a3e9"),
                    "value": 3,
                    "addedBy": ObjectId("61c65e3d912fa75c883bad7e"),
                    "addedDate": ISODate("2021-12-25T22:14:47.745Z")
                },
                {
                    "value": -1,
                    "addedBy": ObjectId("61c7406ce223cf753db8dd67"),
                    "_id": ObjectId("61c797d7e7c81feb75c2a3eb"),
                    "addedDate": ISODate("2021-12-25T22:14:47.746Z")
                }
            ]
        },
        {
            "_id": ObjectId("61c796a349a42520e5c1eba4"),
            "comment": "This initiative should not be passed",
            "votes": [
                {
                    "_id": ObjectId("61c797d7e7c81feb75c2a3e9"),
                    "value": -5,
                    "addedBy": ObjectId("61c65e3d912fa75c883bad7e"),
                    "addedDate": ISODate("2021-12-25T22:14:47.745Z")
                },
                {
                    "value": 2,
                    "addedBy": ObjectId("61c7406ce223cf753db8dd67"),
                    "_id": ObjectId("61c797d7e7c81feb75c2a3eb"),
                    "addedDate": ISODate("2021-12-25T22:14:47.746Z")
                },
                {
                    "value": -3,
                    "addedBy": ObjectId("61c7406ce223cf753db8dd67"),
                    "_id": ObjectId("61c797d7e7c81feb75c2a3eb"),
                    "addedDate": ISODate("2021-12-25T22:14:47.746Z")
                }
            ]
        }
    ]
    }

I would like to get something like this...

    {
    "_id" : ObjectId("61c7969702f8612e6b14db57"),
    "title" : "Important Political Issue",
    "comments" : [ 
        {
            "_id" : ObjectId("61c796a349a42520e5c1eba4"),
            "comment" : "This initiative should be passed",
            "voteSum": 4
        },
        {
            "_id" : ObjectId("61c796a349a42520e5c1eba4"),
            "comment" : "This initiative should not be passed",
            "voteSum": -6
        }
    ]
    }

$project with $sum work perfectly for adding values from the "top level" array of a document...

    db.issues.aggregate([
        {$project: {
            title: 1,
            desc: 1,
            voteSum: {$sum: '$votes.value'}
        }}
    ])

However, I can't figure out how to make it $sum up values for in an array that is in another array.

This doesn't work, it yields zero (0) regardless of what I put in the comment vote values...

    db.issues.aggregate([
        {$project: {
            _id: 1,
            title: 1,
            comments: {
                _id: 1,
                comment: 1,
                voteSum: {$sum: '$comments.votes.value'}
            }}
        }
    ])

Upvotes: 1

Views: 59

Answers (1)

NeNaD
NeNaD

Reputation: 20304

You can do it like this:

  • $map: To iterate over comments array.
  • $sum: To sum all value properties for votes array.
db.collection.aggregate([
  {
    "$set": {
      "comments": {
        "$map": {
          "input": "$comments",
          "as": "comment",
          "in": {
            "_id": "$$comment._id",
            "comment": "$$comment.comment",
            "votes": {
              "$sum": "$$comment.votes.value"
            }
          }
        }
      }
    }
  }
])

Working example

Upvotes: 0

Related Questions