你可以使用.bulkWrite()
這個,它實際上是一個爲什麼存在的主要用例。它只向服務器發送「一個」實際的請求,並且只有一個響應。它仍然是兩個操作,但它們都或多或少捆綁在一起,一般原子反正:
首次
db.junk.bulkWrite([
{ "updateOne": {
"filter": { "a": 1 },
"update": { "$setOnInsert": { "b": [ 5,0 ] } },
"upsert": true
}},
{ "updateOne": {
"filter": { "a": 1 },
"update": { "$min": { "b.0": 5 } }
}}
])
運行會給你一個「更新插入」,注意它的「插入」,並沒有「修正」迴應:
{
"acknowledged" : true,
"deletedCount" : 0,
"insertedCount" : 0,
"matchedCount" : 1,
"upsertedCount" : 1,
"insertedIds" : {
},
"upsertedIds" : {
"0" : ObjectId("5947c412d6eb0b7d6ac37f09")
}
}
當然文檔的樣子:
{
"_id" : ObjectId("5947c412d6eb0b7d6ac37f09"),
"a" : 1,
"b" : [
5,
0
]
}
然後用不同的值運行$min
,你可能會在實際案例:
db.junk.bulkWrite([
{ "updateOne": {
"filter": { "a": 1 },
"update": { "$setOnInsert": { "b": [ 5,0 ] } },
"upsert": true
}},
{ "updateOne": {
"filter": { "a": 1 },
"update": { "$min": { "b.0": 3 } }
}}
])
和響應:
{
"acknowledged" : true,
"deletedCount" : 0,
"insertedCount" : 0,
"matchedCount" : 2,
"upsertedCount" : 0,
"insertedIds" : {
},
"upsertedIds" : {
}
}
其中 「匹配」 2
當然$setOnInsert
,但並不適用,所以結果是:
{
"_id" : ObjectId("5947c412d6eb0b7d6ac37f09"),
"a" : 1,
"b" : [
3,
0
]
}
就像它應該是
操作是否保證是原子的?我擔心另一個針對'{「a」:1}'文檔的查詢可能能夠在'bulkWrite'批次中的第一個'updateOne'和第二個'updateOne'之間運行。 – rid
@rid這是原子,因爲它會得到,當然比發出「兩個請求」,需要等待響應更好。是否有可能在極高的工作量下工作?好吧,如果沒有深入研究,我不會打折。但這是不可能的?那麼後一個問題的答案是肯定的,而且很可能你永遠不會看到這種情況發生。這些是一批事務,MongoDB確實需要跟蹤它們,特別是作爲默認的「有序」操作。此外,它不是有更好的選擇。 –
@rid此外,我認爲你錯過了「IF」(大IF)意味着其他一些操作實際上在兩者之間提交的觀點,那麼它應該不成問題。 '$ min'可以確保這裏提供的任何值,比如'4',那麼它將是一個有效的寫入,然後按照預期被'3'覆蓋。任何值大於默認值或最後修改值的值都會被忽略。所以這實際上是推薦的方法。在同一操作中,不能使用不同或相同的運算符寫入相同的路徑。 –