MongoDB如何匹配属性更新数组对象 无匹配则新增元素到数组
MongoDB数组内元素匹配更新/插入实现方案
你可以根据你使用的MongoDB版本选择以下两种方案:
方案1:聚合管道更新(MongoDB 4.2及以上版本,推荐)
该方案只需单次请求即可完成逻辑,无需业务层额外判断:
// 自定义参数 const targetDocId = "Test-123456789"; // 要操作的根文档id const targetName = "Test3"; // 要匹配的name值 const newSubscriber = { name: targetName, points: 999 }; // 要更新/插入的对象 db.collection.updateOne( { id: targetDocId }, // 根文档过滤条件 [ { $set: { subscribers: { // 第一步:匹配到对应name的元素就替换为新对象,否则保留原元素 $map: { input: "$subscribers", in: { $cond: [ { $eq: ["$$this.name", targetName] }, newSubscriber, "$$this" ] } } } } }, { $set: { subscribers: { // 第二步:判断是否存在匹配的元素,不存在则追加新对象 $cond: [ { $in: [targetName, "$subscribers.name"] }, "$subscribers", { $concatArrays: ["$subscribers", [newSubscriber]] } ] } } } ] )
方案2:常规操作符实现(兼容所有MongoDB版本)
该方案需要两次数据库请求,适合低版本MongoDB使用:
const targetDocId = "Test-123456789"; const targetName = "Test3"; const newSubscriber = { name: targetName, points: 999 }; // 第一步:先尝试更新匹配name的元素 const updateResult = db.collection.updateOne( { id: targetDocId, "subscribers.name": targetName }, { $set: { "subscribers.$": newSubscriber } } ); // 第二步:如果没有匹配到元素,执行追加操作 if (updateResult.modifiedCount === 0) { db.collection.updateOne( { id: targetDocId }, { $push: { subscribers: newSubscriber } } ); }
注意事项
- 如果你的业务允许subscribers数组存在多个相同name的元素,方案1会更新所有重名元素,方案2只会更新第一个匹配到的重名元素
- 如果需要保证subscribers内name唯一,可以在集合上创建
{ id: 1, "subscribers.name": 1 }的唯一索引避免重复数据
内容的提问来源于stack exchange,提问作者iNexx
相关产品推荐
相关产品推荐

