Search code examples
mongodbmongodb-querymongoose-schema

MongoDB nested Aggregate Grouping


Sample Data:

[
    {type: 'partial', jobId: '121', browser: 'chrome', status:'true', jobName:'one'},
    {type: 'partial', jobId: '122', browser: 'chrome', status:'false', jobName:'two'},
    {type: 'partial', jobId: '121', browser: 'firefox', status:'false', jobName:'one'},
    {type: 'partial', jobId: '122', browser: 'firefox', status:'true', jobName:'two'},
    {type: 'full', jobId: '123', browser: 'chrome', status:'true', jobName:'three'},
    {type: 'full', jobId: '123', browser: 'chrome', status:'true', jobName:'three'},
    {type: 'full', jobId: '123', browser: 'chrome', status:'false', jobName:'three'},
    {type: 'full', jobId: '124', browser: 'firefox', status:'false', jobName:'four'},
]

Output Needed:

[
  {
    "type": "partial",
    "browsers": [
      {
        "browser": "chrome",
        "jobIds": [
          {
            "jobId": "121",
            "results": [
              {
                "jobName": "one",
                "status": "true",
              },
            ]
          },
          {
            "jobId": "122",
            "results": [
              {
                "jobName": "two",
                "status": "false"
              },
            ]
          }
        ]
      },
      {
        "browser": "firefox",
        "testIds": [
          {
            "jobId": "121",
            "results": [
              {
                "jobName": "one",
                "status": "false"
              },
            ]
          },
          {
            "jobId": "122",
            "results": [
              {
                "jobName": "two",
                "status": "true"
              },
            ]
          }
        ]
      }
    ]
  },
  {
    "type": "full",
    "browsers": [
      {
        "browser": "chrome",
        "jobIds": [
          {
            "jobId": "123",
            "results": [
              {
                "jobName": "three",
                "status": "true"
              },
              {
                "jobName": "three",
                "status": "true"
              },
              {
                "jobName": "three",
                "status": "false"
              }
            ]
          },
        ]
      },
      {
        "browser": "firefox",
        "testIds": [
          {
            "jobId": "124",
            "results": [
              {
                "jobName": "four",
                "status": "false"
              },
            ]
          },
        ]
      }
    ]
  }
]

I understand how to use group, but then I don't understand how to make the nested grouping. I tried the below query, it is not fetching needed results, I don't know how to proceed further.

   db.collection.aggregate([
  {
    $match: {
      jobId: {
        "$exists": true
      }
    }
  },
  {
    $sort: {
      _id: -1
    }
  },
  {
    $group: {
      _id: {
        type: "$type",
        browser: "$browser",
        jobId: "$jobId"
      },
      results: {
        $push: {
          jobName: "$jobName",
          status: "$status",
          type: "$type",
          jobId: "$jobId"
        }
      }
    }
  },
  {
    $addFields: {
      results: {
        $slice: [
          "$results",
          30
        ]
      }
    }
  },
  {
    $group: {
      _id: "$_id.browser",
      results: {
        $push: {
          results: "$results"
        }
      }
    }
  },
  
])

Need fetch recent 30 results, that's why I added $addFields in query.

https://mongoplayground.net/p/pt3H1O445GA


Solution

    • $group by type, browser and jobId and make results array
    • $group by type and browser and make jobs array
    • $group by type and make browsers array
    db.collection.aggregate([
      { $match: { jobId: { $exists: true } } },
      { $sort: { _id: -1 } },
      {
        $group: {
          _id: {
            type: "$type",
            browser: "$browser",
            jobId: "$jobId"
          },
          results: {
            $push: {
              jobName: "$jobName",
              status: "$status"
            }
          }
        }
      },
      { $addFields: { results: { $slice: ["$results", 30] } } },
      {
        $group: {
          _id: {
            type: "$_id.type",
            browser: "$_id.browser"
          },
          browser: { $first: "$_id.browser" },
          jobIds: {
            $push: {
              jobId: "$_id.jobId",
              results: "$results"
            }
          }
        }
      },
      {
        $group: {
          _id: "$_id.type",
          type: { $first: "$_id.type" },
          browsers: {
            $push: {
              browser: "$_id.browser",
              jobIds: "$jobIds"
            }
          }
        }
      },
      { $project: { _id: 0 } }
    ])
    

    Playground