You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 15:05:54