Collection House:
{
"_id": ObjectId('0001'),
"fruit": "apple",
"entries": [
DBRef('room', ObjectId('1234')),
DBRef('room', ObjectId('5678'))
]
}
Collection rooms:
{
"_id": ObjectId('1234'),
"some": "data"
}
I now want all the rooms normal output (simple find) BUT enriched with a fruit array containing all fruits of houses that contain the rooms (array because a room could be in multiple houses) like:
[
{
"some": "data",
"fruits": ["apple"]
}
]
So I tried aggregating on rooms, doing a lookup on the house, but as I need to search the array, I could not use a normal lookup but one with pipeline. Within the pipeline I would need to create some match-making BUT within that (using map) I cannot get the damn ObjectId out of the DBRef. I know, DBRef is apparently outdated but it’s the DB we have now and I need to work with.
Any help? DB is on version 4.0.22
2
Answers
Playground with the "actual" solution: https://mongoplayground.net/p/HUm05wtOsMJ
Data:
Query:
However, it does not work in my real-life example because "aggregation" does not work with "DBRef"... What it tells as error is that "fieldNames" may not contain "$"... Yeah, thanks for nothing. Apparently mapReduce needs to be used then.
And we need to refactor this DB.
When the example data is inserted with
insertMany()
, the object with fields{ $ref: ..., $id: ... }
get inserted as DBRef objects anyway (image below). And the aggregation pipeline you’ve provided in your answer works in MongoDB 5/6/7, and possibly 4.3.3 onwards.So it’s an issue with "DB is on version 4.0.22" rather than "does not work with DBRef".
Workaround: Since you can’t access
$
-prefixed fields in Mongo 4.0.22, use the technique from this StackOverflow answer (that answer deserves an upvote!)1. Map each DBRef object to an array, so each room becomes an array of
{ k: <field_name>, v: <field_value> }
objectsNote that the
$ref
field is always the 1st object (index 0) in the array and$id
is always the 2nd (index 1).If
$db
existed, it would be the 3rd.Here’s the single demo-stage to do and Mongo Playground:
2. Re-add those fields Map that 2nd value
$id
(index 1) to a field you can lookup, with a non-$-name:3. Use that as the pipeline in your
rooms
aggregation$lookup
stage and match each room’s id with"$rooms.v"
:Final Mongo Playground working MongoDB 4.0.22
Edit: Btw, once you upgrade to at least MongoDB 5.0, then using the
$lookup
Correlated Subqueries Using Concise Syntax, this is what the full aggregation can be simplified to:Mongo Playground for 5.0 onwards.
Example data inserted with DBRef objects: