So these are my two documents
Order document:
{
"_id":"02a33b9a-284c-4869-885e-d46981fdd679",
"context":{
"products":[
{
"id": "e68fc86a-b4ad-4588-b182-ae9ee3db25e4",
"version": "2020-03-14T13:18:41.296+00:00"
}
],
},
}
Product document:
{
"_id":"e68fc86a-b4ad-4588-b182-ae9ee3db25e4",
"context":{
"name": "My Product",
"image": "someimage"
},
}
So I'm trying to do a lookup for a products in order document, but the result should contain combined fields, like so:
"products":[
{
"_id": "e68fc86a-b4ad-4588-b182-ae9ee3db25e4",
"version": "2020-03-14T13:18:41.296+00:00",
"name": "My Product",
"image": "someimage"
}
],
Not sure how to do this, should I do it outside of the lookup, or inside? This is my aggregation
Orders.aggregate([
{
"$lookup":{
"from":"products",
"let":{
"products":"$context.products"
},
"pipeline":[
{
"$match":{
"$expr":{
"$in":[
"$_id",
"$$products.id"
]
}
}
},
{
"$project":{
"_id":0,
"id":1,
"name":"$context.name"
}
}
],
"as":"mergedProducts"
}
},
{
"$project":{
"context":"$context",
"mergedProducts":"$mergedProducts"
}
},
]);
You need to run that mapping outside of $lookup
by running $map along with $arrayElemAt to get single pair from both arrays and then apply $mergeObjects to get one object as a result:
db.Order.aggregate([
{
$lookup: {
from: "products",
localField: "context.products.id",
foreignField: "_id",
as: "productDetails"
}
},
{
$addFields: {
productDetails: {
$map: {
input: "$productDetails",
in: {
_id: "$$this._id",
name: "$$this.context.name"
}
}
}
}
},
{
$project: {
_id: 1,
"context.products": {
$map: {
input: "$context.products",
as: "prod",
in: {
$mergeObjects: [
"$$prod",
{ $arrayElemAt: [ { $filter: { input: "$productDetails", cond: { $eq: [ "$$this._id", "$$prod.id" ] } } }, 0 ] }
]
}
}
}
}
}
])
The goals of the last step is to take take two arrays: products
and productDetails
(the output of $lookup
) and find matches between them. We know there's always one match so we can get only one item $arrayElemAt 0
. As an output of $map
there will be single array containing "merged" documents.