Search code examples
javascriptmongodbaggregatelookup

Mongodb aggregate - group within an array


I have the following aggregate code which looks up all users in a particular category and gets their user details:

  const category: any = await this.categoryModel.aggregate([
      { $match: { _id: categoryID } },
      {
        $lookup: {
          from: "users",
          localField: "_id",
          foreignField: "category",
          as: "users",
        },
      },
      {
        $lookup: {
          from: "user_details",
          localField: "users._id",
          foreignField: "user",
          as: "user_details",
        },
      },
    ]);

However it is being returned as two arrays in the category, one for users and one for user details. How can I project it out so the user_details is an array within each corresponding user?

Currently it outputs like this:

  {
    name: "category 1"
    users: [{_id: "1"},{_id: "2"},{_id: "3"}]
    user_details: [{user: "1", name:"Henry", age:30}, {user: "2", name:"Carol", age:60}, {user: "3", name:"Ben", age:45}]
  },

However, i would like it to look like this:

  {
    name: "category 1"
    users: [
       {_id: "1", user_details: {user: "1", name:"Henry", age:30}
       {_id: "2", user_details: {user: "2", name:"Carol", age:60}
       {_id: "3", user_details: {user: "3", name:"Ben", age:45}
    ]
  },

Input documents see below:

category: {_id: "cat1", name: "category 1"}
users: {_id: "1", category: "cat1"}
user_details: {_id: "ud1", user: "1", name:"Henry", age:30}

Solution

  • One way of doing this is using nested lookups, like this:

    db.category.aggregate([
      {
        $match: {
          _id: "cat1"
        }
      },
      {
        $lookup: {
          from: "users",
          let: {
            categoryId: "$_id",
            
          },
          pipeline: [
            {
              "$match": {
                $expr: {
                  "$eq": [
                    "$category",
                    "$$categoryId"
                  ]
                }
              }
            },
            {
              "$project": {
                category: 0
              }
            },
            {
              $lookup: {
                from: "user_details",
                localField: "_id",
                foreignField: "user",
                as: "user_details",
              },
            }
          ],
          as: "users"
        },
      },
    ])
    

    Playground link.