MongoDB Tree Model: Get all ancestors, Get all descendants

mongodb graphlookup tree
mongodb parent child query
how to get hierarchy data in mongodb
mongodb materialized path
mongodb nested schema
mongodb save nested object
parent child relationship in mongoose
mongodb sets

I have an arbitrary tree structure.

Example data structure:
root
  |--node1
  |     |--node2
  |     |     |--leaf1
  |     |
  |     |--leaf2
  |
  |--node3
        |--leaf3

Each node and leaf has 2 properties: id and name.


The important queries:

1.: A leaf id is given. The query should return the whole path from root to that leaf, with all node's id and name properties.

It's not important if the return value is an sorted array of nodes or if it's an object where the nodes are nested.

Example: If the id of leaf2 is given, the query should return: root(id, name), node1(id, name), leaf2(id, name).


2.: Given any node id: Get the whole (sub)tree. Here it would be nice to retrieve a single object where each node has a children array.


Thoughts, trials and errors:

1.: First I tried to simply model the tree as a single JSON document, but then the query would become impossible: There's no way to find out at which nesting level the leaf is. And if I knew the whole path of ids from root to the leaf, I'd had to use a projection with multiple positional operators and that's not supported by MongoDB at the moment. Additionally it's not possible to index the leaf ids because the nesting can be infinite.

2.: Next idea was to use a flat data design, where each node has an array which contains the node's ancestor ids:

{
  id: ...,
  name: ...,
  ancestors: [ rootId, node1Id, ... ]
}

This way I'd have to do 2 queries, to get the whole path from root to some node or leaf, which is quite nice.

Questions:

If I choose data model 2.: How can I get the whole tree, or a subtree?

Getting all descendants is easy: find({ancestors:"myStartingNodeId"}). But those will of course be not sorted or nested.

Is there a way using the aggregation framework or a completely different data model to solve this problem?

Thank you!

MongoDB is not a graph database and doesn't provide graph traversal operations, so there is no direct solution.

You can use data model you have described in point 2. (nodes with ancestor list), the query find({ancestors:"myStartingNodeId"}) and sort/nest the results in your application code.

Another possibility is to use data model where _id (or some other field) represents full path, for example 'root.node1.node2'. Then graph queries can be transformed to substring queries and correct ordering can be achieved (I hope) just by sorting by this _id.


Update: btw. there are some tree structure patterns described in MongoDB docs: Model Tree Structures in MongoDB

Model Tree Structures with an Array of Ancestors, This page describes a data model that describes a tree-like structure in MongoDB documents You can query by the field ancestors to find all its descendants:. The Array of Ancestors pattern provides a fast and efficient solution to find the descendants and the ancestors of a node by creating an index on the elements of the ancestors field. This makes Array of Ancestors a good choice for working with subtrees. The Array of Ancestors pattern is slightly slower than the Materialized Paths pattern but is more straightforward to use.

Storing Tree like Hierarchy Structures With MongoDB, Note: article is inspired by another article 'Model Tree Structures in MongoDB' by 10gen, Get all node descendants (in order to be able, for example, to select goods from more Tree structure using an Array of Ancestors. However, when dealing with tree structures in the MongoDB, we should be able to perform operations in the tree which include inserting, updating, and removal of nodes, calculate the path which leads to a particular node and then get all the descendants of a particular node.

You can use graphLookup

Documentation: https://docs.mongodb.com/manual/reference/operator/aggregation/graphLookup/

Introduction To Model Tree Structures In MongoDB, However, when dealing with tree structures in the MongoDB, we should be able to perform To get all of the descendants of a particular node, then do it as follows: categoriesAAO.insert({_id:'Ubuntu', parent:'Linux',ancestors:ancpath});. Model Tree Structures with Nested Sets; Note: This article is inspired by another article 'Model Tree Structures in MongoDB' by MongoDB, but does not copy it. Instead, this tutorial provides additional examples on typical operations with tree management. Please refer to the MongoDB article to get a more solid understanding of the approach.

Model Tree Structures with an Array of Ancestors, MongoDB Manual 3.2 Model Tree Structures with an Array of Ancestors. The query to retrieve the ancestors or path of a node is fast and straightforward: db.​categories. You can query by the field ancestors to find all its descendants:. You need a recursive CTE (common table expression): with -- recursive -- some DBMS (e.g. Postgres) require the word "recursive" -- some others (Oracle, SQL-Server) require omitting the "recursive" -- and some (e.g. SQLite) don't bother, i.e. they accept both descendants (parent, descendant, lvl) as ( select parent, child, 1 from source union all select d.parent, s.child, d.lvl + 1 from

Voronenko/Storing_TreeView_Structures_WithMongoDB , Educational repository demonstrating approaches for storing tree structures with NoSQL an Array of Ancestors; Model Tree Structures with Materialized Paths; Model Tree Note: article is inspired by another article 'Model Tree Structures in MongoDB' by MongoDB, but there are two options to get all node descendants. Note: article is inspired by another article 'Model Tree Structures in MongoDB' by 10gen, but does not copy it, but provides additional examples on typical operations with tree management. Please refer for 10gen's article to get more solid understanding of the approach.

Storing Tree like Hierarchy Structures With MongoDB, The following Tree pattern examples model book categories that have hierarchical relationships. You can query by the ancestors to find all its descendants:. Model Tree Structures with an Array of Ancestors; Model Tree Structures with Materialized Paths; Model Tree Structures with Nested Sets; Note: article is inspired by another article 'Model Tree Structures in MongoDB' by MongoDB, but does not copy it, but provides additional examples on typical operations with tree management. Please refer for

Comments
  • I know that MongoDB is no graph database, but I didn't want to use an additional database for that one use case. Maybe another option would be to store both data models, and then query the model that fits best? The point is: The tree will get created once and then will be modified every few months. Though there won't be any relevant overhead. What do you think about it?
  • I don't like model 1 - nested documents - because it's too dynamic. Like you wrote, it's hard or impossible to write queries or index. If the graph grows too much then you can hit document size limit (16 MB). I have bad experience with processing large number of big documents, because of overhead in networking, de/serializing etc. But you can use it. I would store "primary data" in separate documents (model 2) but then you can aggregate them to "model 1" documents as a cache.
  • I know modified my model a bit: I added an children array to each node, so I can easily go forwards and backwards within the tree, and for each node I can see instantly if there are child elements or if it's a leaf. Then concerning model 1: I will completely dismiss it. After the query someone has to create (in my case) Java objects from the data, and it really doesn't matter if it's done by a framework or if I do it myself. This way I can even enrich the data with additional information on the fly.