2011-12-14 33 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函数并让它在服务器上运行。