Search code examples
mongodbcountmongodb-queryaggregate

How can I project top 5 counts and sum the rest in MongoDB?


I have the following documents:

_id: "Team 1"
count: 1200

_id: "Team 2"
count: 1170

_id: "Team 3"
count: 1006

_id: "Team 4"
count: 932

_id: "Team 5"
count: 931

_id: "Team 6"
count: 899

_id: "Team 7"
count: 895

The list is already sorted and everything, I just need to project this as an array of top 5 based on count and then the rest should be summed as 'others'. If possible I'd like to also add the percentage that each element in the list makes up of the full count. Like this:

[
  {"name":"Team 1", "count":1200, "percent":25},
  {"name":"Team 2", "count":1170,"percent":15},
  {"name":"Team 3", "count":1006,"percent":10},
  {"name":"Team 4", "count":932,"percent":5},
  {"name":"Team 5", "count":931,"percent":5},
  {"name":"Other", "count":1794, "percent":40}]
]

Solution

  • another way to do it using $facet since $setWindowFields only works with mongodb v5 or later

    mongoPlayground

    db.collection.aggregate([
        { $sort: { count: -1 } },
        {
          "$facet": {
            others: [
              { "$skip": 5 },
              {
                "$group": {
                  "_id": "others",
                  "count": { "$sum": "$count" }
                }
              }
            ],
            top5: [ { "$limit": 5 } ]
          }
        },
        {
            "$project": { result: { "$concatArrays": [ "$others", "$top5" ] } }
        },
        {
            "$addFields": { totalCount: { "$sum": "$result.count" } }
        },
        { $unwind: "$result" },
        {
          $project: {
            _id: "$result._id",
            count: "$result.count",
            percent: {
              $round: [
                { "$multiply": [ { $divide: [ "$result.count", "$totalCount" ] }, 100 ] },
                0
              ]
            }
          }
        }
      ])