Mongoose6+MongoDB5中UpdateOne引用字段push到数组的实现问题
解决方案
错误原因
你之前的写法触发报错是因为普通update操作默认不支持直接引用文档自身的字段值,$$temp、$$level这类标识在普通更新语法中会被识别为普通字符串,无法解析为字段值,因此触发了index字段的Number类型转换失败报错。另外你第一次尝试中还存在数组字段名书写错误,将Schema中定义的mHierarchy误写为referredHierarchy。
正确实现代码
MongoDB 4.2及以上版本支持聚合管道形式的更新操作,可以直接引用文档自身字段完成原子更新,你的MongoDB 5 + Mongoose 6.0.8环境完全适配该语法,正确写法如下:
MySchema.updateOne( { _id: mySchemaId }, // 第二个参数传数组,标识使用聚合管道更新模式 [ { $set: { mHierarchy: { $concatArrays: [ "$mHierarchy", // 取原有数组的值 [ // 追加的新元素 { userId: mongoose.Types.ObjectId(id), index: "$level" // 直接引用当前文档顶层的level字段值 } ] ] } } } ] )
原理解释
- 当update的第二个参数传入数组时,MongoDB会以聚合管道模式执行更新,支持所有聚合操作符,也可以直接通过
$字段名的形式读取当前文档的任意字段值。 $concatArrays操作符会将原有数组和新元素数组拼接,实现和普通更新中$push完全一致的追加效果,且整个操作是原子性的,不会有并发冲突问题。
注意事项
- 必须将更新逻辑包裹在数组中,否则会被识别为普通更新,无法解析字段引用。
- 注意字段名要和Schema定义保持一致,避免拼写错误。
- 该写法是原子操作,性能和安全性远高于"先查询文档取level值再更新"的非原子写法。
内容的提问来源于stack exchange,提问作者Azin Nilchi
相关产品推荐
相关产品推荐

