【问题标题】:Multiple update of embedded documents' properties嵌入文档属性的多次更新
【发布时间】:2017-10-24 12:51:25
【问题描述】:

我有以下收藏:

{ 
"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)

但只有第一项正在更新。

【问题讨论】:

    标签: mongodb


    【解决方案1】:

    目前这是不可能的。更新中标记multi 表示更新多个根文档。位置运算符只能匹配一个嵌套数组项。 mongodb jira中有这样的feature。您可以投票并等待。

    当前的解决方案只能是加载文档,根据需要进行更新,然后为每个嵌套数组 id 保存或多次原子更新。

    来自mongodb.org的文档:

    目前 $ 运算符仅适用于 查询

    【讨论】:

    • 谢谢,安德鲁。我在 jira 中支持了这个问题。我希望他们会实施它。
    • @1gn1ter: 此功能已获批准,但未安排 :(
    • 4年后,支持吗?
    • @1gn1ter 您对此有什么解决方案吗?我也在找一样的
    【解决方案2】:

    正如 Andrew 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),那么这个命令将什么也不做,只返回空值。我们只需要重新加载文档并重试。如果不是每秒都修改数组,那么这种情况非常少见,不会对性能产生任何影响。

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

    【讨论】:

      【解决方案3】:

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

      https://jira.mongodb.org/browse/SERVER-1243

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-04-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-19
        • 2014-06-12
        • 2023-03-10
        相关资源
        最近更新 更多