Search code examples
javascriptmongodbaggregation

MongoDb aggregate use $sortByCount inside a $group


I am trying to aggregate data using mongoDb to gather data per user. I have the following query:

DB.collection.aggregate([
    { "$facet": {
        "instructions": [
                { $match: { company: ref } },
                { $group: {
                    _id : '$user._id',
                    firstName: { $first: "$user.firstName"},
                    lastName: { $last: "$user.lastName"},
                    total: { $sum: 1 },
                    completed: { $sum: { 
                        "$cond": [
                            { "$eq": [ "$completed.value", true ] }, 
                            1, 0
                        ]}
                    },
                    mostPopularProduct: {
                        $sortByCount: "$productType"  
                    },
                    mostPopularType: {
                        $sortByCount: "$instructionType"  
                    }
                }},
            ]
        }},
        { "$project": {
            "perClient": { "instructions": "$instructions"  }
        }}
    }}
])

I am trying to get the mostPopularProduct (and mostPopularInstruction) in my collection from a string field inside all documents that matches the $match. Basically the product that appears most across all documents. There are a couple of more calculations being done inside the group.

Currently, I am getting the following error: "unknown group operator '$sortByCount'". Now I know it is because it is being used inside the group, which it cannot. But I am unsure how to achieve the desired result. I tried using $sum, but I did not achieve what I wanted. I don't know if I used it incorrectly.

Can someone please point me in the right direction?

EDIT

Okay, so I might have been a bit vague about what I want. Let me clarify a bit.

I have used $sortByCount before, like this:

"mostPopularProduct": [
    { $match: { company: ref } },
    { $sortByCount: "$productType"}
],

The result I got was:

"mostPopularProduct": [
    {
        "_id": "car",
        "count": 14
    }, {
        "_id": "house",
        "count": 2
    }
]

Now, I want to do the exact same thing, but I want it inside of my group, So basically I want to get the following result:

"perClient": {
    "instructions": [
        {
            "_id": "5fd3db7427e9bc610e4daeaa",
            "firstName": "firstName",
            "lastName": "lastName",
            "total": 8,
            "completed": 1,
            // NOW HERE ARE THE FIELDS I WANT
            "mostPopularProduct": [
                {
                    "_id": "car",
                    "count": 3
                }
            ]
        }, // all other clients follow
    ]
}

This is the required result I am trying to achieve with the $sortByCount, inside of a $group.

Here is an example: https://mongoplayground.net/p/XolUjfDCpxn


Solution

  • Sample Documents:

    [
      { userId: 1, productType: "car" },
      { userId: 1, productType: "car" },
      { userId: 1, productType: "bus" },
      { userId: 1, productType: "bus" },
      { userId: 2, productType: "bus" },
      { userId: 2, productType: "bus" }
    ]
    
    • $group by userId and productType and count the sum
    • $group by only userId and prepare the array of productType and count
    db.collection.aggregate([
      {
        "$facet": {
          "instructions": [
            {
              $group: {
                _id: {
                  userId: "$userId",
                  productType: "$productType"
                },
                productTypeCount: { $sum: 1 }
              }
            },
            {
              $group: {
                _id: "$_id.userId",
                mostPopularProduct: {
                  $push: {
                    _id: "$_id.productType",
                    count: "$productTypeCount"
                  }
                }
              }
            }
          ]
        }
      }
    ])
    

    Playground