Ben*_*n M 6 tree ancestor descendant mongodb aggregation-framework
我有一个任意的树结构.
root
|--node1
| |--node2
| | |--leaf1
| |
| |--leaf2
|
|--node3
|--leaf3
Run Code Online (Sandbox Code Playgroud)
每个节点和叶子有2个属性:id和name.
1.:给出了一个叶子id.查询应该返回从root到该leaf的整个路径,包含所有节点id和name属性.
如果返回值是排序的节点数组,或者它是嵌套节点的对象,那么这一点并不重要.
示例:如果给出了idof leaf2,则查询应返回:root(id, name), node1(id, name), leaf2(id, name).
2.:给定任何节点id:获取整个(子)树.在这里检索每个节点都有一个children数组的单个对象会很不错.
1.:首先,我尝试将树简单地建模为单个JSON文档,但随后查询将变得不可能:无法找出叶子的嵌套级别.如果我知道id从根到叶子的整个路径,我必须使用具有多个位置运算符的投影,而MongoDB目前不支持.此外,不可能对叶子进行索引,ids因为嵌套可以是无限的.
2.:下一个想法是使用平面数据设计,其中每个节点都有一个包含节点祖先的数组ids:
{
id: ...,
name: ...,
ancestors: [ rootId, node1Id, ... ]
}
Run Code Online (Sandbox Code Playgroud)
这样我就必须做2个查询,以获得从root到某个节点或叶子的整个路径,这非常好.
如果我选择数据模型2.:我如何获得整个树或子树?
获得所有后代很容易:find({ancestors:"myStartingNodeId"}).但那些当然不会被排序或嵌套.
有没有办法使用聚合框架或完全不同的数据模型来解决这个问题?
谢谢!
这是我最终想出的数据结构。它针对读取查询进行了优化。一些写入查询(例如移动子树)可能会很痛苦。
{
id: "...",
ancestors: ["parent_node_id", ..., "root_node_id"], // order is important!
children: ["child1_id", "child2_id", ...]
}
Run Code Online (Sandbox Code Playgroud)
轻松获取子树的所有文档
轻松获取从某个节点到根的所有文档
轻松检查某个文档是否是某个节点的父/子/祖先/后代
孩子们被分类了。children可以通过更改数组顺序轻松移动
通过ID获取:findOne({ id: "..." })
获取父级:findOne({ children: "..." })
获取所有祖先:首先执行Get by ID,然后获取祖先数组并查找与给定 ID 列表匹配的所有文档
获取所有孩子:find({ 'ancestors.0': "..." })
获取所有后代:find({ ancestors: "..." })
获取x代以内的所有后代:find({ $and: [ {ancestors: "..."}, {ancestors: {$size: x}} ] })
应用程序代码必须注意正确的顺序。
应用程序代码必须构建嵌套对象(也许可以使用 MongoDB 聚合框架实现)。
每个都insert必须使用 2 个查询来完成。
在节点之间移动整个子树必须更新大量文档。