如何用MongoDB聚合展开递归嵌套的kids子文档
如何用MongoDB聚合管道递归展开嵌套的
kids数组? 需求说明
现有一份递归嵌套kids数组的MongoDB文档,需要通过聚合管道将所有层级的kids展开为单层数组,每个元素仅保留_id字段,最终要做成视图(若允许使用$function则实现更简便,纯聚合操作适用于固定层级场景)。
原始文档
{ "_id": "7741cca6-31d4-4652-aa00-a7d547a16a2e", "kids": [ { "_id": "e6c2f07e-899f-40b5-8ac2-9a587f26d67e", "kids": [ { "_id": "e9b35574-add7-490e-ab9d-9b2d425bebf6", "kids": [ { "_id": "25f6e89d-6f77-4a7f-948b-77488578710f" } ] } ] } ] }
期望输出
{ "_id": "7741cca6-31d4-4652-aa00-a7d547a16a2e", "kids": [ { "_id": "e6c2f07e-899f-40b5-8ac2-9a587f26d67e" }, { "_id": "e9b35574-add7-490e-ab9d-9b2d425bebf6" }, { "_id": "25f6e89d-6f77-4a7f-948b-77488578710f" } ] }
尝试过的方案(存在问题)
曾尝试使用$project、$lookup、$unwind、$reduce等操作,其中一段管道代码如下,但最终结果出现数组嵌套数组的问题:
[ { $addFields: { newKids: { $reduce: { input: "$kids.kids.kids", initialValue: [], in: { $concatArrays: [ "$$value", "$$this", ], }, }, }, }, }, { $addFields: { newKids: { $reduce: { input: "$kids.kids", initialValue: "$newKids", in: { $concatArrays: [ "$$value", "$$this", ], }, }, }, }, }, { $addFields: { newKids: { $reduce: { input: ["$kids"], initialValue: "$newKids", in: { $concatArrays: [ "$$value", "$$this", ], }, }, }, }, }, ]
解决方案
方案1:使用$function实现递归(MongoDB 4.4+支持,视图可用)
该方法通过JavaScript函数递归遍历所有层级的kids,收集每个元素的_id,适合任意嵌套层级的场景:
[ { $addFields: { allKids: { $function: { body: function(kidsList) { const result = []; const traverse = (kids) => { kids.forEach(kid => { result.push({ _id: kid._id }); if (kid.kids && kid.kids.length > 0) { traverse(kid.kids); } }); }; traverse(kidsList); return result; }, args: ["$kids"], lang: "js" } } } }, { $project: { _id: 1, kids: "$allKids" } } ]
方案2:纯聚合操作(固定层级场景)
如果嵌套层级是固定的,可以通过$concatArrays结合$map提取每个层级的_id,避免嵌套:
[ { $project: { _id: 1, kids: { $concatArrays: [ // 提取第一层kids的_id { $map: { input: "$kids", as: "k", in: { _id: "$$k._id" } } }, // 提取第二层kids的_id { $map: { input: "$kids.kids", as: "k", in: { _id: "$$k._id" } } }, // 提取第三层kids的_id { $map: { input: "$kids.kids.kids", as: "k", in: { _id: "$$k._id" } } } ] } } } ]
注意:方案2仅适用于已知固定嵌套层级的情况,若层级不固定,建议使用方案1。
内容的提问来源于stack exchange,提问作者dbabob
相关产品推荐
相关产品推荐

