Marcel Jaeschke
Marcel Jaeschke

Reputation: 707

Lookup for a referenced document in an array of embedded documents

I got two collections. One contains an array of objects. These objects own a field with an id to a document in another collection. The goal is to "replace" the ref by the document. Sounds simple but I have no clue how to archive this.

E.G.

Collection "Product"

{ "_id": 1,
  "alias": "ProductA"
},
{ "_id": 2,
  "alias": "ProductC"
}

Collection "Order"

{ "_id": 5765,
  "cart": [
    {
      "product": 1,
      "qty": 7
    }, {
      "product": 2,
      "qty": 6
    }
  ]
}

What I need by a query is this:

{ "_id": 5765,
  "cart": [
    {
      "product": {
        "_id": 1,
        "alias": "ProductA"
      },
      "qty": 7
    }, {
      "product": {
        "_id": 2,
        "alias": "ProductC"
      },
      "qty": 6
    }
  ]
}

I tried a simple lookup, but the array will only contains the products. What do I need to change?

{
    $lookup: {
        from: "products",
        let: {
            tmp: "$cart.product"
        },
        pipeline: [
            {
                $match: {
                    $expr: {
                        $in: ["$_id", "$$tmp"]
                    }
                }
            }
        ],
        as: "cart.product"
    }
}

Thanks for your help.

Upvotes: 0

Views: 70

Answers (1)

prasad_
prasad_

Reputation: 14287

I added a new $addFields stage to transform the output from the $lookup stage - it gets the desired output:

db.order.aggregate([
{
    $lookup: {
        from: "product",
        let: {
            tmp: "$cart.product"
        },
        pipeline: [
            {
                $match: {
                    $expr: {
                        $in: ["$_id", "$$tmp"]
                    }
                }
            }
        ],
        as: "products"
    }
},
{ 
    $addFields: {
         cart: {
             $map: {
                 input: "$cart", as: "ct",
                 in: {
                     product: {
                         $arrayElemAt: [ 
                             { $filter: {
                                   input: "$products", as: "pr",
                                   cond: {
                                      $eq: [ "$$ct.product", "$$pr._id" ]
                                   }
                              }
                          }, 0 ]
                     },
                     qty: "$$ct.qty"
                 }
             }
         }
    }
}
] ).pretty()

Upvotes: 1

Related Questions