如何在MongoDB中更新文档数组内指定_id的对象
MongoDB更新数组中指定_id元素的正确实现
现有代码的问题
你当前编写的更新逻辑本身可以正确定位到数组中匹配_id的元素并执行整值替换,但存在一个问题:你传入的data对象中没有包含原有元素的_id字段,直接替换后会丢失该元素的_id属性,和你预期的结果不符。
正确实现方式
方式1:整对象替换(完全覆盖原有元素)
如果你的需求就是完全替换该元素的所有内容,只需要保留原有的_id,先将_id合并到待替换的对象中再执行更新即可:
const targetId = 'any-id'; const data = { a: 'new-a-data', b: 'new-b-data', c: 'new-c-data' }; // 合并_id到待替换对象 const replaceData = { _id: targetId, ...data }; await model.updateOne( { 'array._id': targetId }, { $set: { 'array.$': replaceData } } );
方式2:仅更新指定字段(更稳妥,不会丢失额外字段)
如果不需要替换整个元素,只需要更新a、b、c三个字段,可以直接指定字段路径更新,不需要构造完整替换对象:
const targetId = 'any-id'; await model.updateOne( { 'array._id': targetId }, { $set: { 'array.$.a': 'new-a-data', 'array.$.b': 'new-b-data', 'array.$.c': 'new-c-data' } } );
方式3:聚合管道更新(适合MongoDB 4.2+版本,兼容性更强)
如果你的MongoDB版本在4.2以上,可以用聚合管道的方式实现,自动合并原有字段和新字段,不需要手动处理_id,也不会丢失元素上可能存在的其他额外字段:
const targetId = 'any-id'; const data = { a: 'new-a-data', b: 'new-b-data', c: 'new-c-data' }; await model.updateOne( { 'array._id': targetId }, [ { $set: { array: { $map: { input: "$array", in: { $cond: [ { $eq: ["$$this._id", targetId] }, { $mergeObjects: ["$$this", data] }, "$$this" ] } } } } } ] )
内容的提问来源于stack exchange,提问作者Yago Cunha
相关产品推荐
相关产品推荐

