2017-06-19 11 views
1

我想插入一個具有默認值的新文檔作爲數組的一部分,或者如果文檔已經存在,則更新該數組的一部分。

我想的是什麼:

db.test.update(
    { "a": 5 }, 
    { $setOnInsert: { "b": [0, 0] }, $min: { "b.0": 5 } }, 
    { upsert: true } 
); 

如果我這樣做,然後我得到:

無法更新 'B' 和 'B.0' 同時

另一個想法是刪除$setOnInsert,只是保留$min,因爲無關和5之間的最小值應該是5

db.test.update(
    { "a": 5 }, 
    { $min: { "b.0": 5 } }, 
    { upsert: true } 
); 

這不會引發錯誤,但現在我得到的文件是:

{ "a" : 5, "b" : { "0" : 5 } } 

我需要0位置5陣列然而,不與0屬性的對象。

我該如何做到這一點?

回答

1

你可以使用.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 
     ] 
} 

就像它應該是

+0

操作是否保證是原子的?我擔心另一個針對'{「a」:1}'文檔的查詢可能能夠在'bulkWrite'批次中的第一個'updateOne'和第二個'updateOne'之間運行。 – rid

+0

@rid這是原子,因爲它會得到,當然比發出「兩個請求」,需要等待響應更好。是否有可能在極高的工作量下工作?好吧,如果沒有深入研究,我不會打折。但這是不可能的?那麼後一個問題的答案是肯定的,而且很可能你永遠不會看到這種情況發生。這些是一批事務,MongoDB確實需要跟蹤它們,特別是作爲默認的「有序」操作。此外,它不是有更好的選擇。 –

+0

@rid此外,我認爲你錯過了「IF」(大IF)意味着其他一些操作實際上在兩者之間提交的觀點,那麼它應該不成問題。 '$ min'可以確保這裏提供的任何值,比如'4',那麼它將是一個有效的寫入,然後按照預期被'3'覆蓋。任何值大於默認值或最後修改值的值都會被忽略。所以這實際上是推薦的方法。在同一操作中,不能使用不同或相同的運算符寫入相同的路徑。 –