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

MongoDB多层嵌套数组匹配聚合新增字段结果异常问题

问题背景

需要检测MongoDB文档内3个位置是否存在值为input的字段,只要存在任意一处匹配,就为文档新增值为"input"的字符串类型element字段。
数据库返回的文档共有3种典型结构:

三类文档结构示例

第一类

{ 
  _id: 1234,
  informations: { ... },
  data_fields: [
    { name: "input", value: "loremipsum" },
    { fieldset_name: "label", value: "loremipsum" }
  ]
}

第二类

{ 
  _id: 2451,
  informations: { ... },
  data_fields: [
    { name: "number", value: "loremipsum" },
    { fieldset_name: "input", value: "loremipsum" },
    {
      fieldset_name: "button",
      value: "loremipsum",
      fieldset_data: [
        [ { "fieldset.name": "home", "fieldset.value": "loremipsum" } ]
      ]
    }
  ]
}

第三类

{ 
  _id: 4561,
  informations: { ... },
  data_fields: [
    {
      fieldset_name: "button",
      value: "loremipsum",
      fieldset_data: [
        [
          { "fieldset.name": "input", "fieldset.value": "loremipsum" },
          { "fieldset.name": "label", "fieldset.value": "loremipsum" }
        ],
        [ { "fieldset.name": "home", "fieldset.value": "loremipsum" } ]
      ]
    }
  ]
}

检测范围

  • data_fields数组下所有元素的name属性
  • data_fields数组下所有元素的fieldset_name属性
  • data_fields数组下元素嵌套的fieldset_data二维数组内,每个子项的fieldset.name属性

预期输出

匹配到input的文档新增element: "input"字段,示例:

{ 
  _id: 1234,
  informations: { ... },
  data_fields: [
    { name: "input", value: "loremipsum" },
    { fieldset_name: "label", value: "loremipsum" }
  ],
  element: "input"
}

原有实现的问题

原有聚合管道使用多层$map做遍历,返回结果为包含null、嵌套空数组的结构,无法得到预期的字符串值:

{ $addFields: {
    element: { $map: {
        input: "$data_fields",
        as: "data_field",
        in: { $cond: {
            if: { $eq: ["$$data_field.name", "input"] },
            then: "$$data_field.name",
            else: { $cond: {
                if: { $eq: ["$$data_field.fieldset_name", "input"] },
                then: "$$data_field.fieldset_name",
                else: { $map: {
                    input: "$$data_field.fieldset_data",
                    as: "fieldsets",
                    in : { $map: {
                        input: "$$fieldsets",
                        as: "fieldset",
                        in: { $cond: {
                            if: { $eq: ["$$fieldset.name", "input"] },
                            then:  "$$fieldset.name",
                            else: "$$REMOVE"
                         }}
                    }}
                }}
            }}
        }}
    }}
}}

实际返回错误示例:

{ 
  _id: 1234,
  informations: { ... },
  data_fields: [
    { name: "input", value: "loremipsum" },
    { fieldset_name: "label", value: "loremipsum" }
  ],
  element: [null, "input", [null, null, null], null]
}

修正方案

原有代码存在3个核心错误:

  1. $map返回结果与输入数组长度完全一致,不匹配的位置会默认返回null,无法直接得到单值结果
  2. 嵌套遍历fieldset_data时没有做扁平化处理,也没有过滤空值,最终生成多层嵌套结构
  3. 注意:嵌套字段的键名是带点的字符串fieldset.name,不是嵌套对象结构,原有代码写$$fieldset.name会被MongoDB解析为取fieldset对象下的name属性,和实际字段名不匹配。

使用以下聚合管道即可实现需求:

[
  {
    $addFields: {
      element: {
        $reduce: {
          input: "$data_fields",
          initialValue: [],
          in: {
            $concatArrays: [
              "$$value",
              // 匹配当前项name字段
              { $cond: [{ $eq: ["$$this.name", "input"] }, ["input"], []] },
              // 匹配当前项fieldset_name字段
              { $cond: [{ $eq: ["$$this.fieldset_name", "input"] }, ["input"], []] },
              // 遍历嵌套的fieldset_data二维数组
              {
                $reduce: {
                  input: { $ifNull: ["$$this.fieldset_data", []] },
                  initialValue: [],
                  in: {
                    $concatArrays: [
                      "$$value",
                      {
                        $reduce: {
                          input: "$$this",
                          initialValue: [],
                          in: {
                            $concatArrays: [
                              "$$value",
                              // 匹配嵌套项的fieldset.name字段
                              { $cond: [{ $eq: ["$$this.fieldset.name", "input"] }, ["input"], []] }
                            ]
                          }
                        }
                      }
                    ]
                  }
                }
              }
            ]
          }
        }
      }
    }
  },
  {
    $addFields: {
      element: {
        $cond: [
          { $gt: [{ $size: "$element" }, 0] },
          { $arrayElemAt: ["$element", 0] },
          "$$REMOVE"
        ]
      }
    }
  }
]

逻辑说明

  • 全程使用$reduce做数组遍历,通过$concatArrays拼接匹配结果,不匹配的位置直接拼接空数组,不会产生null值
  • 对可能不存在的fieldset_data字段用$ifNull兜底为空数组,避免遍历不存在字段时报错
  • 二维fieldset_data使用双层$reduce遍历,所有层级的匹配结果都会被扁平化为一维数组
  • 最后判断匹配数组长度,存在匹配项时取第一个值(所有匹配值均为input,取任意项即可)作为字符串类型的element值,无匹配则不生成该字段,完全符合预期。

内容的提问来源于stack exchange,提问作者Eviane

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 11:06:19