Reputation: 7732
I have a collection named Container with array of embedded documents called embeddedMany. Each embedded document is referencing several other documents named Referenced and these references are stored in array called referenceMany. The document looks like this.
{
"_id" : ObjectId("5a312337ea5cb32d30005d25"),
"embeddedMany" : [
{
"referencedMany" : [
DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d24"), "myDb"),
DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d23"), "myDb")
]
},
{
"referencedMany" : [
DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d23"), "myDb")
DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb")
]
},
{
"referencedMany" : [
DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d24"), "myDb")
DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb")
]
}
],
}
Now I need to find all embedded documents that reference certain document. Let's say this one: DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb")
.
I need the resulting document to look like this:
{
"_id" : ObjectId("5a312337ea5cb32d30005d25"),
"embeddedMany" : [
{
"referencedMany" : [
DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d23"), "myDb")
DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb")
]
},
{
"referencedMany" : [
DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d24"), "myDb")
DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb")
]
}
],
}
I read this very similar problem. So I guess I need to use aggregation and filter the embeddedMany field. My aggregation looks like this so far:
db.Container.aggregate(
[
{
$match: {
"embeddedMany.referencedMany.$id": ObjectId("5a312337ea5cb32d30005d22")
}
},
{
$project: {
"embeddedMany": {
"$filter": {
"input": "$embeddedMany",
"as": "embedded",
"cond": {
"$eq": [
"$$embedded.referencedMany.$id",
ObjectId("5a312337ea5cb32d30005d22")
]
}
}
}
}
},
]
);
And this is where I hit the wall. Because the MongoDB has the outstanding bug that prevents me from comparing $id
in the $eq
expression. There are some mentions about using $objectToArray
as hack but I couldn't pull it off all together.
Any help would be highly appreciated.
Upvotes: 0
Views: 1074
Reputation: 42342
You don't need to break down the objects nor worry about the bug you referenced if the result you want is like the example you gave. Simply use comparisons between DBRef objects in your pipeline (example done in mongo
shell:
mydbref = DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb");
db.dbref.aggregate([
{$match:{"embeddedMany.referencedMany":mydbref}},
{"$project":{"embeddedMany":{
"$filter":{
"input":"$embeddedMany",
"cond":{
"$in":[{$literal:mydbref},"$$this.referencedMany"]
}
}
}}}
])
{
"_id" : ObjectId("5a312337ea5cb32d30005d25"),
"embeddedMany" : [
{
"referencedMany" : [
DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d23"), "myDb"),
DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb")
]
},
{
"referencedMany" : [
DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d24"), "myDb"),
DBRef("Referenced", ObjectId("5a312337ea5cb32d30005d22"), "myDb")
]
}
]
}
Upvotes: 1
Reputation: 75914
You can use the below $project
stage for comparing dbref ids.
$objectToArray
to convert DBRef into key value pairs.
Next step is the $filter
the dbref key value pairs to only contain id key value pairs.
Next step to $let
+ $map
expression to project only id values.
Final step is to $filter
"embeddedMany" array by comparing passed in ObjectId values against the referencedMany id values using $in
expression.
{"$project":{"embeddedMany":{
"$filter":{
"input":"$embeddedMany",
"as":"embedded",
"cond":{
"$in":[
ObjectId("5a312337ea5cb32d30005d22"),
{
"$map":{
"input":"$$embedded.referencedMany",
"as":"referenced",
"in":{
"$arrayElemAt":[
{
"$let":{
"vars":{
"id":{
"$filter":{
"input":{"$objectToArray":"$$referenced"},
"as":"r",
"cond":{"$eq":["$$r.k",{"$literal":"$id"}]}
}
}
},
"in":"$$id.v"
}
},
0
]
}
}
}
]
}
}
}
}}
Upvotes: 1