简体   繁体   中英

count field dynamically under $bucket boundaries in mongo aggregate

I am using Mongo aggregate framework, suppose if i am having collection structure like this

 [ { _id: 123, name: "john", age: 30, fruit: "apple", }, { _id: 345, name: "moore", age: 45, fruit: "mango", }, { _id: 545, name: "carl", age: 30, fruit: "grape", }, { _id: 96, name: "shelby", age: 25, fruit: "apple", }, { _id: 86, name: "loris", age: 48, fruit: "mango", }, { _id: 76, name: "carl", age: 55, fruit: "grape" } ]

I want to query and create a pipeline such that it return the count of particular fruit which lie under the duration which $bucket boudaries have created: for example result should look like this...

 [ { "_id": Specific_Boudary, "userCount": Number_Of_Users_Lie, "fruitsLie": [ {fruit_names_of_user_in_this_boundaries: fruit_counts}, ] }, { "_id": 0, "userCount": 3, "fruitsLie": [ {apple: 2}, {grape: 1} ] }, { "_id": 40, "userCount": 2, "fruitsLie": [ {mango: 2} ] }, { "_id": "more than 50", "userCount": 1, "fruitsLie": [ {grape: 1} ] } ]

so under age 30 we have 3 users, in which 2 eats apple and 1 eats grape so fruitsLie field is responsible for this calculation.

how many approaches we can have to achieve the solution for this problem with specific $bucket boudaries and please explain thoroughly each stage, I am new to aggregate and currently learning...

This is one way of doing this:

db.collection.aggregate([
  {
    "$bucket": {
      "groupBy": "$age",
      "boundaries": [
        0,
        31,
        41,
        51,
        
      ],
      "default": "More than 50",
      "output": {
        "users": {
          $push: "$$ROOT"
        }
      }
    }
  },
  {
    "$unwind": "$users"
  },
  {
    "$group": {
      "_id": {
        _id: "$_id",
        fruit: "$users.fruit"
      },
      "count": {
        "$sum": 1
      },
      
    }
  },
  {
    "$group": {
      "_id": "$_id._id",
      "fruitsLie": {
        "$push": {
          "$concatArrays": [
            [],
            [
              [
                "$$ROOT._id.fruit",
                "$$ROOT.count"
              ]
            ]
          ]
        }
      },
      usersCount: {
        $sum: "$$ROOT.count"
      }
    }
  },
  {
    "$addFields": {
      "fruitsLie": {
        "$map": {
          "input": "$fruitsLie",
          "as": "item",
          "in": {
            "$arrayToObject": "$$item"
          }
        }
      }
    }
  }
])

Playground link.

In this query, we do the following:

  1. Using $bucket, we group the documents by age into 4 buckets, (0-30), (31-40), (41-50), and (>50). We collect all the users within a bucket into an array.

  2. Now, we unwind the users array, using $unwind.

  3. Now, using $group, we calculate, the counts for each fruit within each bucket.

  4. Again using $group, now we accumulate counts for each bucket, into fruitsLie array.

  5. Finally, using $arrayToObject , we convert elements of fruitLie array to a object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM