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

使用Mongoose遍历嵌套数组并重命名字段

问题描述

我需要将集合中所有文档的ss_characteristics数组内,所有键名为ssfollow_sinusitis的字段重命名为sinusitis,同时保留对应的值。我尝试用Mongoose的updateMany结合$rename操作符实现,但发现MongoDB的$rename不支持遍历嵌套数组,这个方法无效。

尝试的无效代码:

await Form.updateMany(
  { 'ss_characteristics.$.ssfollow_sinusitis': { $exists: true } },
  { $rename: { 'ss_characteristics.$.ssfollow_sinusitis': 'ss_characteristics.$.sinusitis' } }
);

数据表示例:

const all_forms = await Form.find({})

// console.log(all_forms) 输出如下:
[
  {
    _id: new ObjectId("6413adfdea76122e6fcdefc6"),
    general_details: {
      name: 'YEYO Rae',
    },
    ss_characteristics: [
      {
        sinusitis: 'No',
        _id: new ObjectId("6450fb3d4155fbd24cb69a73")
      },
      {
        sinusitis: 'No',
        _id: new ObjectId("6450fba24155fbd24cb69ab0")
      }
    ]
  },
  {
    _id: new ObjectId("6413adfdea76122e6fcdefc6"),
    general_details: {
      name: 'OSLAVI Hig',
    },
    ss_characteristics: [
      {
        ssfollow_sinusitis: 'No',
        _id: new ObjectId("6450fb3d4155fbd24cb69a73")
      },
      {
        ssfollow_sinusitis: 'No',
        _id: new ObjectId("6450fba24155fbd24cb69ab0")
      }
    ]
  }
]

解决方案

因为$rename无法遍历数组中的所有元素,你可以使用MongoDB 4.2+支持的聚合管道式更新来实现,通过$map遍历数组并修改字段名:

await Form.updateMany(
  { "ss_characteristics.ssfollow_sinusitis": { $exists: true } },
  [
    {
      $set: {
        ss_characteristics: {
          $map: {
            input: "$ss_characteristics",
            as: "item",
            in: {
              $mergeObjects: [
                // 移除原字段
                { $unsetField: { input: "$$item", field: "ssfollow_sinusitis" } },
                // 添加新字段,值来自原字段(如果存在),否则保留已有值
                { sinusitis: { $ifNull: ["$$item.ssfollow_sinusitis", "$$item.sinusitis"] } }
              ]
            }
          }
        }
      }
    }
  ]
);

代码说明:

  1. 查询条件{ "ss_characteristics.ssfollow_sinusitis": { $exists: true } }:只匹配包含目标字段的文档,避免无意义的更新。
  2. $map遍历ss_characteristics数组的每个元素:
    • $unsetField移除元素中的ssfollow_sinusitis字段;
    • $mergeObjects将移除后的元素与新的sinusitis字段合并,用$ifNull兼容两种场景:原元素有ssfollow_sinusitis就用它的值,否则保留已有的sinusitis值。

如果你的MongoDB版本低于4.2,不支持聚合管道更新,可以用循环处理每个文档的方式(适合数据量不大的场景):

const forms = await Form.find({ "ss_characteristics.ssfollow_sinusitis": { $exists: true } });

for (const form of forms) {
  form.ss_characteristics.forEach(item => {
    if (item.ssfollow_sinusitis !== undefined) {
      item.sinusitis = item.ssfollow_sinusitis;
      delete item.ssfollow_sinusitis;
    }
  });
  await form.save();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:38:23