Join two collections with $lookup
Build a $lookup stage in the visual builder, and use the autocomplete that keeps working on the joined fields afterwards.
$lookup is the stage people write wrong most often, mostly because nothing tells you whether the
field names are right until the pipeline returns an empty array.
Use the form helper
- Open a query tab on the collection you are joining from.
- Switch the editor to Builder.
- Add a
$lookupstage. The form asks for the foreign collection, the local field, the foreign field, and the output name. - Preview the stage. Automatic refresh is off by default, so ask for the preview, or turn auto-refresh on and it will re-run after a pause in typing. Each stage previews its own output, so you see the joined array appear rather than finding out at the end. A preview carries a 20-document safety limit unless you turn it off.
If the joined array is empty, the local and foreign fields do not match in type. An ObjectId in
one collection and its string form in the other is the usual cause, and it looks identical in a
tree view. Switch that field to JSON view to see which one is {"$oid": ...}.
The part that pays off afterwards
Once the $lookup is in the pipeline, autocomplete knows about the fields it produced. Type the
output name and a dot, and you get the foreign collection’s schema, nested paths included.
That keeps working through the stages that reshape documents: $project, $group, $count,
$facet, $bucket and $unset. A field an earlier stage created is still offered eight stages
later, which is the thing this editor does that a plain shell does not. Where a stage’s output
cannot be derived, a computed $replaceRoot for example, the whole document is kept instead.
Switch back to code whenever you like
Visual and code modes round-trip a pipeline the builder can read, so you can start in the form and finish by typing.
Two limits are worth knowing. A pipeline the builder cannot fully read is reduced to the part it
understood, and that reduction is written back on your first edit, so surrounding statements,
comments, a trailing .explain() and a second options argument do not survive the trip. And
undo covers structural edits only: adding, moving, duplicating, enabling and clearing a stage,
up to 50 entries. Typing inside a stage body is not undoable from the pipeline history.
Watch the plan
A $lookup without an index on the foreign field is a collection scan per input document. Run the
pipeline, open Explain, and check. Reading an explain plan
covers what to look for.
Next
- Aggregation builder reference
- The aggregation cheat sheet, which runs in your browser