MongoDB's $graphLookup trying to get a tree structure

$graphLookup is not producing the hierarchy of dependencies - it performs a recursive search of connected documents, but results are flattened into the single-dimension array. Here is the quote from the documentation:

For each matching document, $graphLookup takes the value of the _id and checks every document in the tree collection for a matching parent value. For each match, $graphLookup adds the matching document in the from collection to an array children. This step continues recursively until no more matching documents are found, or until the operation reaches a recursion depth specified by the maxDepth parameter.

I.e. it searches for dependent documents recursively, but each found document is added to same children array of the parent document no matter how 'deep' the child is located.


Note - you don't see Child 1.1 with its connected Subchild 1.1.1 because you are filtering out these documents in match stage:

{ $match: { parent: { $exists: false } } }

that selects only documents which don't have a parent - "Root node 1" and "Root node 2". If you will remove this filter, then all other documents with the hierarchy of their dependants will be returned:

{
    "name" : "Child 1.1",
    "children" : [ 
        { "name" : "Subchild 1.1.1" }
    ]
},
{
    "name" : "Child 1.2"
    "children" : []
},
{
    "name" : "Root node 1",
    "children" : [ 
        { "name" : "Subchild 1.1.1" }, 
        { "name" : "Child 1.2" }, 
        { "name" : "Child 1.1" }
    ]
},
{
    "name" : "Root node 2",
    "children" : []
},
{
    "name" : "Subchild 1.1.1"
    "children" : []
}

If you don't want to mix children from different 'depth' of tree in single children array, then take a look at interesting comment in documentation

Setting the maxDepth field to 0 is equivalent to a non-recursive $lookup search stage.

It means that each document will get all its direct children into the children array, and after that lookup will stop without any further recursive search. Output will be

{
    "name" : "Child 1.1",
    "children" : [ 
        { "name" : "Subchild 1.1.1" }
    ]
},
{
    "name" : "Child 1.2"
    "children" : []
},
{
    "name" : "Root node 1",
    "children" : [ 
        { "name" : "Child 1.2" }, 
        { "name" : "Child 1.1" }
    ]
},
{
    "name" : "Root node 2",
    "children" : []
},
{
    "name" : "Subchild 1.1.1"
    "children" : []
}

Tags:

Mongodb