如何检查mongodb文档在读取之后但在写入之前是否进行了修改



考虑将Address文档ID嵌入到User文档中的用例。线程12同时运行,然后是Check results线程。

用户:

addresses: [1, 2, 3]

异步线程1:

user = userCollection.find(userId)
user.addresses.push(4)
userCollection.update(user)

异步线程2:

user = userCollection.find(userId)
user.addresses.push(5)
userCollection.update(user)

检查结果:

user = userCollection.find(userId)
user.addresses.includes(4) // result is non-deterministic
user.addresses.includes(5) // result is non-deterministic

我是否需要在应用程序级别实现自己的文档级锁,以防止多线程应用程序覆盖其他线程当前正在写入的数据?

也许我缺少一个可以附加到数组的内置原子函数?但是查找/替换的情况如何?我不只是想把一个新值"推"到数组中,而是找到一个被删除的旧ID,然后将其删除。同时,另一个线程想添加到数组中。老实说,我不确定最简单的解决方案是什么。我已经用psuedojavascript写了这个问题,但我在这个项目中使用了golang。

根据官方文件,

在MongoDB中,写操作是单个文档级别的原子操作,即使该操作修改了单个文档中的多个嵌入文档。

您不需要太在意单个文档的原子性。对于给定的示例,您可以简单地使用聚合管道进行更新,该管道可用于MongoDB v4.2+。

db.collection.update({
"userId": 1
},
[
{
"$set": {
"addresses": {
"$setUnion": [
{
"$filter": {
"input": "$addresses",
"as": "a",
"cond": {
$ne: [
"$$a",
3    // element you want to remove
]
}
}
},
// element you want to add
[
4
]
]
}
}
}
])

这是Mongo游乐场供您参考。

如果您需要处理多文档原子性,您可以选择事务,这可用于MongoDB v4.0+

最新更新