MongoDB中限制单用户关联应用数量的最优实现方式探讨
实现每个用户关联应用数量限制的方法
最简单的实现方式(适用于低并发场景)
直接在插入新的用户-应用关联记录前,先查询该用户已有的关联数量:
- 执行计数查询:
db.collection.countDocuments({ sub: 1234 }) - 如果返回值小于5,再执行插入操作:
db.collection.insertOne({ sub: 1234, appId: 5678 })
这种方式逻辑直观,但存在竞态风险:高并发下可能有多个请求同时查到计数为4,随后都完成插入,导致该用户的关联数量超过上限。
更贴合MongoDB特性的高级实现方式(原子性,无竞态)
利用MongoDB的文档嵌套设计和原子更新操作,彻底避免并发问题,同时提升查询效率:
步骤1:调整集合结构
将每个用户的所有关联应用ID存入一个数组,单个文档对应单个用户:
{ "sub": 1234, "appIds": [5678, 9012, 3456, 7890, 2345] }
步骤2:创建唯一索引
确保每个用户在集合中只有一个文档:
db.collection.createIndex({ sub: 1 }, { unique: true })
步骤3:原子性添加应用
使用updateOne配合$push的$slice参数,实现原子性添加并限制数组长度,同时通过$ne避免重复添加同一应用:
db.collection.updateOne( { sub: 1234, appIds: { $ne: 5678 } }, { $push: { appIds: { $each: [5678], $slice: -5 } } }, { upsert: true } )
$slice: -5表示只保留数组的最后5个元素,自动截断超出上限的部分upsert: true表示如果该用户不存在,则自动创建新文档- 整个更新操作是原子执行的,完全避免并发竞态问题
优势
- 原子性:无需事务,MongoDB原生保证操作的一致性
- 高效性:查询用户所有关联应用只需一次单文档查询,无需聚合或多文档扫描
- 自动去重+限流:一步操作完成重复检查、添加和长度限制
内容的提问来源于stack exchange,提问作者Jim Jin
相关产品推荐
相关产品推荐

