能否在MongoDB中将upsert与remove操作结合为单步原子调用?
实现方案
MongoDB原生不支持在单次原子操作中同时执行findOneAndDelete和upsert两种语义,但可以通过软标记+单原子findOneAndUpdate的方式完全实现你要的逻辑,无需额外的复杂操作,也不会有并发冲突问题。
前置准备
先给你的关联ID字段(也就是你说的key X)建立唯一索引,避免重复插入:
db.yourCollection.createIndex({ "x": 1 }, { unique: true })
核心原子操作实现
直接用带聚合管道的findOneAndUpdate即可,所有操作全程原子:
const result = db.yourCollection.findOneAndUpdate( // 按关联ID查询 { x: "你的关联ID值" }, // 聚合管道更新逻辑 [ { $set: { // 已匹配标记:旧文档存在则设为true,新插入则设为false matched: { $cond: { if: { $eq: [ { $type: "$matched" }, "missing" ] }, then: false, else: true } }, // 新插入文档需要的其他B字段,仅在文档不存在时赋值 msgType: { $ifNull: [ "$msgType", "response" ] }, content: { $ifNull: [ "$content", "你的B文档内容" ] }, // 其他自定义字段以此类推 } } ], { upsert: true, // 返回修改前的文档 returnDocument: "before" } )
结果判断逻辑
- 如果
result.value不为null:说明之前已经存在相同关联ID的文档A,result.value就是你要的A的内容,后续可以后台定时清理所有matched: true的文档即可。 - 如果
result.value为null:说明之前没有相同关联ID的文档,已经成功插入B文档,等待后续匹配即可。
其他可选方案
如果你不想保留已匹配的文档,也可以用MongoDB事务包裹findOneAndDelete和insert两次操作,不过性能会比软标记方案低,不适合高并发的消息流场景。
内容的提问来源于stack exchange,提问作者Niels Harremoes
相关产品推荐
相关产品推荐

