MongoDB重命名非结构化数组内指定字段及$rename报错解决
报错原因
$rename操作符本身不支持搭配数组位置符(包括$匹配符、$[]全位置符)动态定位数组内的字段做重命名,你写的name.$.middlename属于动态数组字段路径,MongoDB会直接拦截执行,抛出你看到的错误。
正确实现方案
根据你使用的MongoDB版本选择对应方案即可:
方案1:MongoDB 4.2及以上版本(推荐,支持聚合管道更新)
直接用updateMany配合聚合更新管道,遍历name数组完成字段重命名,单条语句即可批量处理所有符合条件的文档,不会漏改数组内多个符合条件的元素:
db.md_carrierInformation.updateMany( { "name.middlename": { $exists: true } }, [ { $set: { name: { $map: { input: "$name", in: { $mergeObjects: [ "$$this", { $cond: [ { $not: ["$$this.middlename"] }, {}, { mid_name: "$$this.middlename" } ] } ] } } } } }, { $unset: "name.middlename" } ] )
执行逻辑说明:
- 先筛选出所有
name数组中存在middlename字段的文档 - 用
$map遍历name数组的每一个元素,对存在middlename的元素,新增mid_name字段并赋值为原middlename的值 - 最后统一移除数组中所有的旧
middlename字段,完成重命名
方案2:MongoDB 4.2以下版本(不支持聚合管道更新)
低版本无法在单条更新语句中完成数组遍历操作,需要逐文档查询后修改再写回:
db.md_carrierInformation.find({ "name.middlename": { $exists: true } }).forEach(doc => { const newNameArr = doc.name.map(item => { if (item.hasOwnProperty('middlename')) { item.mid_name = item.middlename delete item.middlename } return item }) db.md_carrierInformation.updateOne( { _id: doc._id }, { $set: { name: newNameArr } } ) })
注意事项
- 执行更新前建议先在测试环境验证,或者提前备份目标集合,避免误改数据
- 不要尝试用数组全位置符
$[]搭配$rename实现需求,$rename从设计上就不支持对数组内嵌字段做动态重命名
内容的提问来源于stack exchange,提问作者manoj adhikari
相关产品推荐
相关产品推荐

