skip to Main Content

I’m trying to populate a double array object but in an aggregate so I am utilizing the $lookup function. The collection looks something like this:

{
  foo: [
    {
      bar: [
        {
          _id: ObjectId('63f508eedd2962118c37ea36')
        }
      ]
    }
  ]
}

My lookup looks like:

{
  $lookup: {
    from: "collection",
    localField: "foo.bar",
    foreignField: "_id",
    as: "foo.bar",
  },
}

which results in

{
  foo: {
    bar: [
      {
        _id: ObjectId('63f508eedd2962118c37ea36'),
        field1: "helloworld"
      }
    ]
  }
}

where what I actually want is

{
  foo: [
    {
      bar: [
        {
          _id: ObjectId('63f508eedd2962118c37ea36'),
          field1: "helloworld"
        }
      ]
    }
  ]
}

Any ideas on how to achieve what I want in an aggregate?

2

Answers


  1. Seems a direct map with $lookup for the nested array is not possible.

    1. $lookup – Join the collection collection and return the bars array field.

    2. $set – Set foo array.

      2.1. $map – Iterate element in foo array.

      2.1.1. $mergeObjects – Merge current iterated foo element with the result of 2.1.1.1.

      2.1.1.1. A document with a bar field which contains the result of 2.1.1.1.1.

      2.1.1.1.1. $map – Iterate element in bar array.

      2.1.1.1.1.1. $mergeObjects – Merge the current iterated bar element with the result of 2.1.1.1.1.1.1.

      2.1.1.1.1.1.1. $first – Get the first matching element from the bars array by _ids.

    3. $unset – Remove bars array.

    db.from.aggregate([
      {
        $lookup: {
          from: "collection",
          localField: "foo.bar._id",
          foreignField: "_id",
          as: "bars"
        }
      },
      {
        $set: {
          foo: {
            $map: {
              input: "$foo",
              as: "foo",
              in: {
                $mergeObjects: [
                  "$$foo",
                  {
                    bar: {
                      $map: {
                        input: "$$foo.bar",
                        as: "bar",
                        in: {
                          $mergeObjects: [
                            "$$bar",
                            {
                              $first: {
                                $filter: {
                                  input: "$bars",
                                  cond: {
                                    $eq: [
                                      "$$bar._id",
                                      "$$this._id"
                                    ]
                                  }
                                }
                              }
                            }
                          ]
                        }
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      },
      {
        $unset: "bars"
      }
    ])
    

    Demo @ Mongo Playground

    Login or Signup to reply.
  2. Maybe it would be simpler to $unwind at foo level first, do the $lookup and $group back the result?

    db.from.aggregate([
      {
        "$unwind": "$foo"
      },
      {
        $lookup: {
          from: "collection",
          localField: "foo.bar._id",
          foreignField: "_id",
          as: "foo.bar"
        }
      },
      {
        $group: {
          _id: "$_id",
          foo: {
            $push: "$foo"
          }
        }
      }
    ])
    

    Mongo Playground

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search