MongoDB保存文档时添加自增rowNumber:单查询实现与竞争条件规避
MongoDB实现自动递增rowNumber的原子方案
直接通过「查询集合总数+1」的方式生成rowNumber,在并发写入场景下必然会出现竞争——多个请求同时读取到相同的总数,导致最终多个文档的rowNumber重复,而且这种方式需要两次独立操作,效率也不高。
要解决这个问题,最可靠的方式是用单独的计数器集合配合MongoDB的原子更新操作,一次完成计数递增与新值获取,彻底避免竞争:
1. 初始化计数器集合
先创建一个专门存储序列值的集合(比如命名为counters),并初始化一条计数器记录:
db.counters.insertOne({ _id: "rowNumberCounter", sequence_value: 0 })
2. 原子生成rowNumber并插入文档
使用findOneAndUpdate(MongoDB 4.0+支持)原子性地递增计数器并返回最新值,再用这个值插入目标文档:
// 原子操作获取下一个rowNumber const counterResult = await db.collection('counters').findOneAndUpdate( { _id: "rowNumberCounter" }, { $inc: { sequence_value: 1 } }, // 原子递增 { returnDocument: 'after', upsert: true } // 返回更新后的文档,不存在则自动创建 ); const newRowNumber = counterResult.value.sequence_value; // 插入目标文档 await db.collection('your_target_collection').insertOne({ rowNumber: newRowNumber, // 你的其他业务字段 });
核心优势
findOneAndUpdate是原子操作,MongoDB会为这个操作加锁,多个并发请求会排队执行,绝不会出现两个请求拿到相同rowNumber的情况;- 计数器的更新是单查询完成的,后续的文档插入可以和它结合成一个事务(需MongoDB副本集/分片集群环境),保证操作的一致性。
如果你的MongoDB版本较低(<4.0),可以用findAndModify替代findOneAndUpdate,逻辑完全一致。
内容的提问来源于stack exchange,提问作者Arpit Shukla
相关产品推荐
相关产品推荐

