2016-12-08 172 views
2

比方說,我有一個這樣的文件:MongoDB的UPSERT在子文檔中數組並返回更新的子文檔

{ 
    "_id" : ObjectId(1234), 
    "name": "foo", 
    "bars": [ 
     { "name": "n1", "myBool": true }, 
     { "name": "n2", "myBool": false }, 
     { "name": "n3", "myBool": false } 
    ] 
} 

我想找到name(或整個子文檔,它並不真正的問題),並且針對bars中的第一個子文檔改變爲true,對於在原子操作中的給定_id,當前爲false。例如,對於上面的數據,我想在_id等於ObjectId(1234)的文檔中返回n2並將其設置爲myBooltrue對於n2

我該如何做到這一點?

回答

2

運行findAndModify命令,將參數new設置爲true,從而返回修改過的文檔而不是原始文件。

更新應使用$ positional operator,它標識數組中的元素以更新,而不顯式指定數組中元素的位置。爲此,數組字段必須作爲查詢文檔的一部分出現。

輸出的文檔具有value字段,它包含命令返回的文檔:

var result = db.runCommand({ 
    "findAndModify": "collection", 
    "query": { 
     "_id" : 1234, 
     "bars.myBool": false 
    }, 
    "update": { "$set": { "bars.$.myBool": true } }, 
    "new": true 
}); 
printjson(result.value); 

樣本輸出

{ 
    "_id" : 1234, 
    "name" : "foo", 
    "bars" : [ 
     { 
      "name" : "n1", 
      "myBool" : true 
     }, 
     { 
      "name" : "n2", 
      "myBool" : true 
     }, 
     { 
      "name" : "n3", 
      "myBool" : false 
     } 
    ] 
} 
+0

是否可以調整,以僅返回子文檔而不是整個文件?即我想知道哪個子文檔(名稱)已更改。 – Johan

+1

不幸的是,你不能在原子更新中做到這一點。您必須手動過濾數組,即運行兩個單獨的查詢1.使用'_id「查找文檔:1234, 」bars.myBool「:false }'然後運行上述更新,它將返回修改過的文檔。當你得到這兩個文檔時,你可以在'bars'數組子文檔中找到差異。 – chridam

+0

不幸的是,這不會在高度併發的環境中工作,因爲兩個或多個線程可以同時執行此操作。即我不能先讀取,然後比較結果,因爲另一個線程可能已經更新了「myBool」,然後我不知道哪一個被更改了。 – Johan

0

更新時間: 可能是這周圍的工作,但滿足您的要求,請使用以下查詢

db.test.findAndModify({ 
    query: { "_id": 123456, "bars.myBool": false}, 
    update: {$set: {"bars.$.myBool": true}}, 
     fields: { 
      "bars": {$elemMatch: {"myBool" : false }} 
     } 
}) 

黑客是否會返回將要修改的原始文檔。

它返回

{ 
    "_id" : 123456, 
    "bars" : [ 
     { 
      "name" : "n2", 
      "myBool" : false 
     } 
    ] 
} 

那裏你可以得到正在更新

文檔,以便result包含單個子文檔,通過它可以得到的名稱數組。

瞭解更多關於findAndModify

+0

謝謝,但我的問題是,我不知道名稱。我想在原子操作中獲取名稱(並更新myBool)。 – Johan

+0

對不起,不理解OP,一旦檢查更新的答案。 –

相關問題