Graph lookup helps find connected data that links to itself, like family trees or company hierarchies.
Graph lookup for recursive data in MongoDB
db.collection.aggregate([
{
$graphLookup: {
from: "collectionName",
startWith: "$fieldToStart",
connectFromField: "fieldToFollow",
connectToField: "fieldToMatch",
as: "outputArray",
maxDepth: <number>, // optional
depthField: "depthFieldName" // optional
}
}
])from is the collection to search recursively.
startWith is the value to start the search from.
db.employees.aggregate([
{
$graphLookup: {
from: "employees",
startWith: "$managerId",
connectFromField: "employeeId",
connectToField: "managerId",
as: "subordinates"
}
}
])db.categories.aggregate([
{
$graphLookup: {
from: "categories",
startWith: "$_id",
connectFromField: "_id",
connectToField: "parentId",
as: "allSubcategories",
maxDepth: 3,
depthField: "level"
}
}
])db.products.aggregate([
{
$graphLookup: {
from: "products",
startWith: "$componentId",
connectFromField: "_id",
connectToField: "componentId",
as: "allComponents"
}
}
])This inserts employees with managers and finds all subordinates for each employee recursively.
db.employees.insertMany([
{ employeeId: 1, name: "Alice", managerId: null },
{ employeeId: 2, name: "Bob", managerId: 1 },
{ employeeId: 3, name: "Charlie", managerId: 1 },
{ employeeId: 4, name: "David", managerId: 2 },
{ employeeId: 5, name: "Eve", managerId: 2 }
])
// Find all subordinates under each employee
const result = db.employees.aggregate([
{
$graphLookup: {
from: "employees",
startWith: "$managerId",
connectFromField: "employeeId",
connectToField: "managerId",
as: "subordinates"
}
}
]).toArray()
printjson(result)Time complexity depends on the size and depth of the graph.
Space complexity grows with the number of connected documents found.
Common mistake: mixing up connectFromField and connectToField causes no results.
Use $graphLookup when you need recursive search; use $lookup for simple joins.
$graphLookup helps find connected data recursively in the same collection.
It is useful for hierarchical or network data like employees or categories.
Remember to set correct fields for starting point and connections.
Practice
$graphLookup stage in MongoDB aggregation?Solution
Step 1: Understand the role of $graphLookup
$graphLookup is designed to recursively find related documents by following references within the same collection, useful for hierarchical data.Step 2: Compare with other options
Options B, C, and D describe other MongoDB operations unrelated to recursive lookup.Final Answer:
To recursively search connected documents within the same collection -> Option DQuick Check:
$graphLookup = recursive search [OK]
- Confusing $graphLookup with $match filtering
- Thinking $graphLookup updates documents
- Assuming $graphLookup creates indexes
$graphLookup stage in a MongoDB aggregation pipeline?Solution
Step 1: Identify correct field references
In $graphLookup,startWithuses the field to start recursion, usually a reference like "$managerId". TheconnectToFieldis the field in the foreign documents to match against the start value, here "_id". TheconnectFromFieldis the field in the foreign document used for the next recursion, here "managerId".Step 2: Match syntax with options
{"$graphLookup": {"from": "employees", "startWith": "$managerId", "connectFromField": "managerId", "connectToField": "_id", "as": "reportingHierarchy"}} correctly usesstartWith: "$managerId",connectFromField: "managerId", andconnectToField: "_id". Others swap these or use incorrect field names.Final Answer:
{"$graphLookup": {"from": "employees", "startWith": "$managerId", "connectFromField": "managerId", "connectToField": "_id", "as": "reportingHierarchy"}} -> Option BQuick Check:
Correct field mapping = {"$graphLookup": {"from": "employees", "startWith": "$managerId", "connectFromField": "managerId", "connectToField": "_id", "as": "reportingHierarchy"}} [OK]
- Swapping connectFromField and connectToField
- Missing $ in startWith field
- Using wrong field names for connections
categories with documents:{"_id": 1, "name": "Electronics", "parent": null}{"_id": 2, "name": "Computers", "parent": 1}{"_id": 3, "name": "Laptops", "parent": 2}What will be the result of this aggregation?
[ { "$graphLookup": { "from": "categories", "startWith": "$parent", "connectFromField": "parent", "connectToField": "_id", "as": "ancestors" } } ]for the document with
_id: 3?Solution
Step 1: Understand the recursive lookup
Starting from the document with _id 3,startWithuses itsparentfield which is 2. Then it finds documents where_idmatches 2, then recursively finds parents of 2, which is 1.Step 2: Trace the ancestors found
The recursion finds documents with _id 2 and then _id 1, so the 'ancestors' array contains both documents.Final Answer:
An array 'ancestors' containing documents with _id 2 and 1 -> Option AQuick Check:
Recursive parents = [2, 1] [OK]
- Assuming only direct parent is returned
- Confusing connectFromField and connectToField
- Expecting syntax error incorrectly
{ "$graphLookup": { "from": "employees", "startWith": "$managerId", "connectFromField": "managerId", "connectToField": "_id", "as": "team" } }Why might this pipeline fail or return empty results when run on an employee document with no
managerId field?Solution
Step 1: Check the startWith field value
If the document has nomanagerIdfield,startWithevaluates to null or undefined, so the recursion has no starting point.Step 2: Understand impact on results
Without a valid start value, $graphLookup returns an empty array for 'team' because it cannot find connected documents.Final Answer:
BecausestartWithis null or missing, recursion cannot start -> Option CQuick Check:
Missing startWith value = empty results [OK]
- Thinking connectFromField/connectToField swap causes empty results
- Assuming 'as' field name causes failure
- Ignoring missing 'from' collection errors
employees where each document has _id and managerId. You want to find all employees under a manager recursively, including the manager. Which $graphLookup configuration correctly achieves this?Solution
Step 1: Define the recursion direction
To find all employees under a manager, start with the manager's_id. Then find employees whosemanagerIdmatches this_id, recursively.Step 2: Match fields in $graphLookup
startWithshould be$_id(the manager's id).connectToFieldismanagerId(field in employees to match), andconnectFromFieldis_id(field to match against for next level).Step 3: Verify options
{"$graphLookup": {"from": "employees", "startWith": "$_id", "connectFromField": "_id", "connectToField": "managerId", "as": "team"}} matches this logic exactly. {"$graphLookup": {"from": "employees", "startWith": "$_id", "connectFromField": "managerId", "connectToField": "_id", "as": "team"}} swaps connectFromField and connectToField incorrectly. The options starting with$managerIdare wrong for this use case.Final Answer:
{"$graphLookup": {"from": "employees", "startWith": "$_id", "connectFromField": "_id", "connectToField": "managerId", "as": "team"}} -> Option AQuick Check:
Start with manager _id, connectFromField = _id, connectToField = managerId = {"$graphLookup": {"from": "employees", "startWith": "$_id", "connectFromField": "_id", "connectToField": "managerId", "as": "team"}} [OK]
- Swapping connectFromField and connectToField
- Starting with $managerId instead of $_id
- Confusing direction of recursion
Ready to prove it?
Pass the test and this pattern moves unknown
