Mongodb 多次更新嵌入文档';性质

Mongodb 多次更新嵌入文档';性质,mongodb,Mongodb,我有以下收藏: { "Milestones" : [ { "ActualDate" : null, "Index": 0, "Name" : "milestone1", "TargetDate" : ISODate("2011-12-13T22:00:00Z"), "_id" : ObjectId("4ee89ae7e60fc615c42e28d1")}, { "A

我有以下收藏:

{ 
"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、里程碑列表。_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)

但只有第一项正在更新。

这在当前是不可能的。更新中的标志
multi
表示更新多个根文档。位置运算符只能匹配一个嵌套数组项。在mongodb jira中有这样的情况。你可以投票等待

当前解决方案只能是加载文档、根据需要进行更新并为每个嵌套数组id保存回或多个原子更新

从以下网址获取文件:

当前,$运算符仅适用于 质疑


正如安德鲁·奥西奇(Andrew Orsich)所回答的,这在目前是不可能的,至少不像你希望的那样。但是加载文档、修改数组然后将其保存回将起作用。风险在于其他进程可能会同时修改数组,因此您可能会覆盖其更改。为了避免这种情况,您可以使用乐观锁定,尤其是当数组不是每秒修改一次时

  • 加载文档,包括一个新属性:
    里程碑\u版本
  • 根据需要修改阵列
  • 保存回mongodb,但现在在
    里程碑\u版本
    上添加一个查询约束,并将其递增:

    db.Projects.findAndModify({
        query: {
            _id: your_project_id,
            milestones_version: expected_milestones_version
        },
        update: {
            $set: {
                Milestones: modified_milestones
            },
            $inc: {
                milestones_version: 1
            }
        },
        new: 1
    })
    
  • 如果另一个进程在我们之前修改了里程碑数组(因此也修改了
    里程碑\u版本
    ),那么这个命令将不执行任何操作,只返回null。我们只需要重新加载文档并重试。如果阵列不是每秒修改一次,那么这种情况将非常罕见,并且不会对性能产生任何影响


    此解决方案的主要问题是必须逐个编辑每个项目(no
    multi:true
    )。您仍然可以编写javascript函数并在服务器上运行。

    根据他们的JIRA页面,“此新功能从MongoDB 3.5.12开发版本开始提供,并包含在MongoDB 3.6生产版本中”


    Thx,安德鲁。我在吉拉对这个问题投了赞成票。我希望他们能实现它。@1gn1ter:这项功能已被批准,但没有计划:(4年后,它是否受支持?@1gn1ter你对此有什么解决方案吗?我正在寻找相同的解决方案