如何使用MongoDB的$graphLookup获取树形结构所有递归子节点
MongoDB递归查询嵌套树形层级结构实现方案
这个需求完全可以在MongoDB中实现。你当前使用$graphLookup已经可以拉取到所有层级的子孙节点,只是默认返回的是平级数组,需要额外增加聚合阶段将平级数据拼装为嵌套树形结构即可。
第一步:修正原有查询的问题
你原有查询的第一个匹配阶段语法有误,缺少$match操作符,同时查询子孙节点的$graphLookup参数配置错误,导致只能查到一级子节点:
// 错误的匹配阶段写法 { name: "Eliot" } // 正确写法需要包裹$match { $match: { name: "Eliot" } }
第二步:完整聚合查询语句
以下是可以直接返回嵌套树形结构的完整聚合语句,适配MongoDB 4.4及以上版本:
db.xmantree.aggregate([ // 1. 匹配目标根节点 { $match: { name: "Eliot" } }, // 2. 递归查询所有层级的子孙节点 { $graphLookup: { from: "xmantree", startWith: "$_id", connectFromField: "_id", // 当前节点的_id作为下一级的parentId匹配条件 connectToField: "parentId", as: "allDescendants", // 可选:限制递归深度,比如最多查3级就写maxDepth:2(深度从0开始计数) // maxDepth: 2 } }, // 3. 递归查询所有父节点(和你原有逻辑一致) { $graphLookup: { from: "xmantree", startWith: "$parentId", connectFromField: "parentId", connectToField: "_id", as: "parents" } }, // 4. 自定义函数将平级的子孙节点拼装为嵌套树形结构 { $addFields: { children: { $function: { body: function(rootId, descendants) { // 递归构建树形结构的工具函数 const buildTree = (parentId) => { return descendants .filter(item => item.parentId === parentId) .map(item => ({ ...item, children: buildTree(item._id) })) } return buildTree(rootId) }, args: ["$_id", "$allDescendants"], lang: "js" } } } }, // 可选:移除临时存储所有子孙的平级字段 { $unset: "allDescendants" } ])
运行结果说明
执行上述查询后,你将得到符合预期的嵌套结构,每一级子节点都会自动携带自己的children字段,示例输出如下:
{ "_id" : 2, "name" : "Eliot", "parentId" : 1, "parents" : [ { "_id" : 1, "name" : "Dev" } ], "children" : [ { "_id" : 3, "name" : "Ron", "parentId" : 2, "children" : [ { "_id" : 5, "name" : "Asya", "parentId" : 3, "children" : [ ] } ] }, { "_id" : 4, "name" : "Andrew", "parentId" : 2, "children" : [ { "_id" : 6, "name" : "Dan", "parentId" : 4, "children" : [ ] } ] } ] }
如果你使用的是MongoDB 4.4以下版本,不支持$function,可以在查询得到平级的allDescendants数组后,在应用层做树形结构拼装,逻辑和上述函数中的buildTree逻辑完全一致。
内容的提问来源于stack exchange,提问作者DD DD
相关产品推荐
相关产品推荐

