考虑一下将Address文档ID嵌入到User文档中的用例。线程1和2同时运行,然后是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已被删除,然后删除它。同时,另一个线程想要添加到数组中。老实说,我不知道什么是最简单的解决办法。我用psuedo-javascript编写了这个问题,但是我在这个项目中使用了golang。
发布于 2022-07-25 17:19:22
据官方医生称,
在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
]
]
}
}
}
])这是供您参考的蒙戈游乐场。
如果需要处理多文档原子性,可以选择交易记录,这是MongoDB v4.0+可用的。
https://stackoverflow.com/questions/73112796
复制相似问题