如何在MongoDB文档数组中实现元素的新增与更新?
用MongoDB原生操作实现数组元素的新增与更新
需求
现有包含attributes数组的customer文档,需对该数组执行元素新增和已有元素更新(按key匹配)操作。
现有数据
文档中的attributes数组:
[ { key: "email", value: "abc@efg.com" }, { key: "name", value: "Somebody" } ]
待处理元素集合
需要新增或更新的元素:
[ { key: "email", value: "new_email@efg.com" }, { key: "mobile", value: "1234567890" } ]
期望结果
最终的attributes数组:
[ { key: "email", value: "new_email@efg.com" }, { key: "name", value: "Somebody" }, { key: "mobile", value: "1234567890" } ]
现有Node.js客户端实现(希望替换为MongoDB原生操作)
const { attributes, uid } = req.body; const customer: any = await getCustomer({ uid }); const oldAttributes = customer?.attributes.filter((attr: any) => !attributes.find((att: any) => att.key === attr.key)); const updatedAttributes = [...oldAttributes, ...attributes]; const response = await updateCustomer({ uid }, { $set: { attributes: updatedAttributes } } );
MongoDB原生解决方案
以下两种方式均可实现需求,且均为原子操作:
方法1:结合$pull与$push操作符
先移除所有与待更新元素key匹配的旧元素,再添加所有待更新元素:
const { attributes, uid } = req.body; const response = await updateCustomer( { uid }, { $pull: { attributes: { key: { $in: attributes.map(attr => attr.key) } } }, $push: { attributes: { $each: attributes } } } );
逻辑:$pull会删除原数组中所有key存在于待更新列表的元素,随后$push将所有待更新元素添加到数组末尾,语法简洁,适用于大多数场景。
方法2:使用聚合管道更新(MongoDB 4.2+支持)
通过聚合管道直接在数据库层面完成过滤与拼接,逻辑更直观:
const { attributes, uid } = req.body; const response = await updateCustomer( { uid }, [ { $set: { attributes: { $concatArrays: [ // 保留原数组中key不在待更新列表里的元素 { $filter: { input: "$attributes", cond: { $not: { $in: ["$$this.key", attributes.map(attr => attr.key)] } } } }, // 添加待更新的元素集合 attributes ] } } } ] );
逻辑:先过滤掉原数组中需要更新的元素,再将过滤后的数组与待更新元素集合拼接,最后用$set替换原数组,无需拆分操作,所有逻辑在单个管道中完成,适合复杂数组处理场景。
内容的提问来源于stack exchange,提问作者Paritosh Verma
相关产品推荐
相关产品推荐

