使用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"] } } ] } } } } } ] );
代码说明:
- 查询条件
{ "ss_characteristics.ssfollow_sinusitis": { $exists: true } }:只匹配包含目标字段的文档,避免无意义的更新。 $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
相关产品推荐
相关产品推荐

