MongoDB:在更新中使用`$expr:{$lt:[{$size:"$members"},3]}` 能否防止竞态条件?
我有一个MongoDB集合,其中每个文档包含一个数组字段 members。我想在添加新元素时强制数组长度最大为3。我正在考虑的一种做法如下更新:
db.collection.updateOne(
{
_id: docId,
$expr: { $lt: [{ $size: "$members" }, 3] }
},
{
$push: { members: newMember }
}
)
我的问题是:
- 如果有多个客户端并发执行此更新,数组有可能超过3 个元素吗?
- 换句话说,
$expr条件与$push条件在这种情况下是否能够共同确保原子性,还是可能出现竞态条件?
对于在并发写入下在MongoDB中安全地强制数组大小约束的任何指导或最佳实践,我将不胜感激。先行感谢您的帮助!
解决方案
MongoDB保证所有单文档操作(包括 updateOne)在文档级别上是原子性的。这意味着筛选条件和更新将作为对数据库的一个不可分割的原子操作来评估并应用;在 $expr 的大小检查与 $push 之间,不能有其他写入插入。
这种做法是安全的,但还有更好的方法来解决你的问题。你可以通过在数据库层面使用 Schema Validator 来强制数组永远不超过3 个元素的规则:
db.runCommand({
collMod: "yourCollection",
validator: {
$jsonSchema: {
bsonType: "object",
properties: {
members: {
bsonType: "array",
maxItems: 3,
description: "members array must not exceed 3 elements"
}
}
}
},
validationLevel: "strict",
validationAction: "error"
})
有了 validationAction: "error",任何会把数组推到超过3 项的写入都会被直接拒绝,返回WriteError。这是你的安全网,无论写入来源为何。
一旦应用了这个Validator,你只需要执行一个简单的更新查询;任何违反该规则的更新都会被拒绝:
db.yourCollection.updateOne(
{ _id: docId },
{ $push: { members: newMember } }
)
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。