'How to create nested array inside $group in MongoDB?

After some of the aggregation pipeline stages, my MongoDB Document has the following format:

{
    "key": "A",
    "status": "To Do",
    "val": 4
  },
  {
    "key": "A",
    "status": "Done",
    "val": 1
  },
  {
    "key": "A",
    "status": "To Do",
    "val": 3
  },
  {
    "key": "A",
    "status": "Done",
    "val": 2
  },
  {
    "key": "B",
    "status": "Done",
    "val": 5
  },
  {
    "key": "B",
    "status": "Done",
    "val": 6
  }

Expected output:

  1. Group by key
  2. Group by status
  3. Push val
  {
    "key": "A",
    "status_val": [
      {
        "status": "To Do",
        "val": [
          3,
          4
        ]
      },
      {
        "status": "Done",
        "val": [
          1,
          2
        ]
      }
    ]
  },
  {
    "key": "B",
    "status_val": "Done",
    "val": [
      5,
      6
    ]
  }

Here is what I tried:

db.collection.aggregate([
          {
            $group: {
            _id: {
              
              key:"$key",
              status:"$status"
            },
              v: {
               $push:  "$val"
               }
           }
         },
         {
            $group: {
            _id: "$_id.key",
              status_val: {
               $addToSet: {
                 status: "$_id.status",
                 val: "$_id.v"
               }
           }
         }},
         {
    $project: { _id: 0,key:"$_id",status_val:1 }
  }
]).pretty()

But I get the wrong output:

[
  {
    "key": "B",
    "status_val": [
      {
        "status": "Done"
      }
    ]
  },
  {
    "key": "A",
    "status_val": [
      {
        "status": "Done"
      },
      {
        "status": "To Do"
      }
    ]
  }
]

How to get nested array inside $group?



Solution 1:[1]

You're correctly running $group twice but this line needs to be changed:

val: "$_id.v"

v is not a part of _id, your data after first $group looks like this:

{
    "_id": { "key": "B, "status": "Done" },
    "v": [ 5, 6 ]
}

try:

db.collection.aggregate([
    {
        $group: {
            _id: { key: "$key", status: "$status" },
            val: { $push: "$val" }
        }
    },
    {
        $group: {
            _id: "$_id.key",
            status_val: {
                $push: {
                    status: "$_id.status",
                    val: "$val"
                }
            }
        }
    },
    {
        $project: {
            _id: 0,
            key: "$_id",
            status_val: 1
        }
    }
])

Mongo Playground

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1