2011-12-14 67 views
3

我有以下的集合:嵌入文檔的屬性的多個更新

{ 
"Milestones" : [  
    {  "ActualDate" : null, 
    "Index": 0, 
    "Name" : "milestone1", 
    "TargetDate" : ISODate("2011-12-13T22:00:00Z"),   
    "_id" : ObjectId("4ee89ae7e60fc615c42e28d1")},   
    {  "ActualDate" : null,  
    "Index" : 0,  
    "Name" : "milestone2", 
    "TargetDate" : ISODate("2011-12-13T22:00:00Z"),   
    "_id" : ObjectId("4ee89ae7e60fc615c42e28d2") } ] 
, 
"Name" : "a", "_id" : ObjectId("4ee89ae7e60fc615c42e28ce") 
} 

我想更新文件明確:已指定_id,Milestones._id和ActualDate的列表爲空。 我DOTNET我的代碼如下所示:

var query = Query.And(new[] { Query.EQ("_id", ObjectId.Parse(projectId)), 
    Query.In("Milestones._id", new BsonArray(values.Select(ObjectId.Parse))), 
Query.EQ("Milestones.ActualDate", BsonNull.Value) });     

var update = Update.Set("Milestones.$.ActualDate", DateTime.Now.Date);  

Coll.Update(query, update, UpdateFlags.Multi, SafeMode.True); 

或在本地代碼:

db.Projects.update({ "_id" : ObjectId("4ee89ae7e60fc615c42e28ce"), "Milestones._id" : { "$in" : [ObjectId("4ee89ae7e60fc615c42e28d1"), ObjectId("4ee89ae7e60fc615c42e28d2"), ObjectId("4ee8a648e60fc615c41d481e")] }, "Milestones.ActualDate" : null },{ "$set" : { "Milestones.$.ActualDate" : ISODate("2011-12-13T22:00:00Z") } }, false, true) 

但只有第一項被更新。

回答

10

這在當前是不可能的。更新中的標誌multi表示更新多個根文檔。位置運算符只能匹配一個嵌套數組項。 mongodb jira中有這樣的feature。你可以投票並等待。

當前的解決方案只能加載文檔,根據需要進行更新併爲每個嵌套數組ID更新或多次更新原子。

從技術文檔在mongodb.org

目前的$操作僅適用於第一個匹配的項目在 查詢

+0

THX,安德魯。我已經在傑拉提出了這個問題。我希望他們會執行它。 – 1gn1ter 2011-12-14 14:22:12

1

如回答安德魯Orsich,這是不可能的時刻,至少不是你想的。但加載文檔,修改數組然後將其保存回去將會起作用。風險在於某個其他進程可能會在此期間修改數組,因此您會覆蓋其更改。爲了避免這種情況,可以使用樂觀鎖定,特別是如果數組沒有每秒修改一次。

  1. 負荷的文檔,包括一個新的屬性:milestones_version
  2. 修改數組需要
  3. 保存回MongoDB的,但現在在milestones_version添加查詢約束,並加:

    db.Projects.findAndModify({ 
        query: { 
         _id: your_project_id, 
         milestones_version: expected_milestones_version 
        }, 
        update: { 
         $set: { 
          Milestones: modified_milestones 
         }, 
         $inc: { 
          milestones_version: 1 
         } 
        }, 
        new: 1 
    }) 
    

如果另一個進程改性里程碑陣列(以及因此milestones_version)我們以前那樣,然後這個命令什麼也不做,只是返回null。我們只需要重新加載文件並重試。如果陣列沒有每秒修改一次,那麼這將非常罕見,並且不會對性能產生任何影響。

該解決方案的主要問題是您必須逐個編輯每個項目(否multi: true)。你仍然可以編寫一個JavaScript函數並讓它在服務器上運行。