MongoDB批量请求下出现重复文档问题求助
问题分析与解决方案:MongoDB并发更新导致重复文档
问题根源
你遇到的是并发竞态条件问题:
短时间内大量请求同时执行时,多个请求会同时通过exists判断(此时目标文档还未被创建),随后各自执行create操作,最终生成重复文档。因为exists和create是两个独立的数据库操作,中间存在时间窗口,并发请求会钻这个空子,破坏数据一致性。
解决方案
1. 创建唯一复合索引(核心保障)
先给likeCollection创建post_id和user_id的唯一复合索引,从数据库层面强制阻止重复文档插入:
// 在MongoDB shell或初始化脚本中执行 db.likeCollection.createIndex({ post_id: 1, user_id: 1 }, { unique: true })
这个索引会确保post_id与user_id的组合唯一,即便并发请求同时尝试插入重复数据,MongoDB会直接抛出唯一键冲突错误,避免重复文档生成。
2. 改造代码为原子操作(消除竞态窗口)
将分步的exists+create/delete改为原子操作,彻底去掉中间的时间窗口:
// 尝试删除匹配的文档 const deletedDoc = await likeCollection.findOneAndDelete({ post_id, user_id }); // 若未找到可删除的文档(即此前不存在),则插入新文档 if (!deletedDoc) { try { await likeCollection.create({ post_id, user_id }); } catch (err) { // 捕获唯一键冲突错误(处理极端并发下的最后插入竞争) if (err.code === 11000) { // 可忽略该错误,说明已有其他请求完成了插入操作 } else { throw err; } } }
关键说明
- 唯一索引是数据一致性的最后防线,即便代码层面的原子操作出现极端情况,数据库层面也能阻止重复数据写入。
- 捕获错误码11000的唯一键冲突,是为了处理极端并发场景:当多个请求同时进入
create分支时,只有第一个请求能成功插入,后续请求触发的错误可直接忽略,因为目标数据已经存在。
内容的提问来源于stack exchange,提问作者Epple
相关产品推荐
相关产品推荐

