Lot’s a questions on Stack Overflow regarding Mongo DB, Aggregate, and lookup. However, I could not find direct answers to the issue I am struggling with.
Suppose we have two collections: Support and Images. The Support document has a property called instructions that is an array of objects, which each contain an image property that is the string value of the images collection id. During the aggregation, the support document is found during match (returning one support document), then I need the instructions array objects to each get their "image" property replaced with the found images from the lookup, and ultimately return the root support object with only the instrucitons.image property changed.
No new properties added, only use the instructions.image tag from each object in the instructions array to get the correct images, then replace those strings with the actual image value from the images array.
- How is this done?
- Is there any way to get access to the "localfield" in the lookup without using "let" if I was to use a lookup pipeline?
- Could this all be done inside of a lookup pipeline?
- What is the most efficient way of doing this?
DB.support = [
{
_id: ObjectId("12345"),
title: "Support",
instructions: [
{
image: "image-id-string-one"
},
{
image: "image-id-string-two"
},
{
image: "image-id-string-three"
},
]
}]
DB.images = [
{
_id: ObjectId("11111111"),
id:"image-id-string-one",
image: "actual-image-one"
},
{
_id: ObjectId("222222222"),
id:"image-id-string-two",
image: "actual-image-two"
},
{
_id: ObjectId("333333333"),
id:"image-id-string-three",
image: "actual-image-three"
}]
db.collection('support').aggregate([
{
"$match": {
"title": "Support"
}
},
// Let's say we match on title and expect only one record from above match
{
"$unwind": "$instructions"
},
{
"$lookup": {
"from": "images",
"localField": "instructions.image",
"foreignField": "id",
"as": "images"
}
},
{
"$unwind": "$images"
},
{
"$set": {
"instructions.image": "$images.image"
}
},
// Remove images array artifact from lookup from object.
{
"$unset": ["images"]
}])
// So that the return object would look like this
{
_id: ObjectId("12345"),
title: "Support",
instructions: [
{
image: "actual-image-one"
},
{
image: "actual-image-two"
},
{
image: "actual-image-three"
},
]}
// NOTE: I have tried so many ways to try to get to the above object but nothing.
2
Answers
You were almost there.
The pipeline you show would result in a separate support document for each instruction, with the image field already replaced with the desired value.
From that point you would need to:
This might look like:
Playground
Result from adding those 2 stages:
A lookup and a project would be sufficient
image
document and you just want to extract the required fields use$map
so that you don’t have to manually specify all the fields that are not needed.playground
playground
or using
$unset
playground