MongoDB nested lookup with 3 levels

The cause of your ‘troubles’ is the second aggregation stage – { $unwind: "$address" }. It removes record for party with _id: 4 (because its address array is empty, as you mention) and produces two records for parties _id: 1 and _id: 5 (because each of them has two addresses).

  • To prevent removing of parties without addresses you should set preserveNullAndEmptyArrays option of $unwind stage to true.

  • To prevent duplicating of parties for its different addresses you should add $group aggregation stage to your pipeline. Also, use $project stage with $filter operator to exclude empty address records in output.

db.party.aggregate([{
  $lookup: {
    from: "address",
    localField: "_id",
    foreignField: "party_id",
    as: "address"
  }
}, {
  $unwind: {
    path: "$address",
    preserveNullAndEmptyArrays: true
  }
}, {
  $lookup: {
    from: "addressComment",
    localField: "address._id",
    foreignField: "address_id",
    as: "address.addressComment",
  }
}, {
  $group: {
    _id : "$_id",
    name: { $first: "$name" },
    address: { $push: "$address" }
  }
}, {
  $project: {
    _id: 1,
    name: 1,
    address: {
      $filter: { input: "$address", as: "a", cond: { $ifNull: ["$$a._id", false] } }
    } 
  }
}]);

Leave a Comment