【问题标题】:MongoDb update multiple Specific Embedded documents within the same arrayMongoDb 更新同一数组中的多个特定嵌入文档
【发布时间】:2019-05-11 15:34:59
【问题描述】:

我有一个用例,其中视图允许用户更新多个对象并一次提交,我怎样才能使这个原子化?

{_id: parent,
 childrenA: [
   {_id: child1, property: "update-me", property2: "leave-alone"},
   {_id: child2, property: "leave-alone", property2: "update-me"}
 ],
 propertyA: "update-me",
 propertyB: "leave-alone", //someone else needs to be able to update this concurrently with this change.
 childrenB:[
   {property: "update-me", property2: "leave-alone"},
   {property: "leave-alone", property2: "update-me"}
 ],

}

属性可能是也可能不是另一个嵌套对象数组。 这是否可能以编程方式进行?

编辑:我需要提一下,我无法可靠地更新整个文档 在某些情况下,可以替换嵌入的文档(地址,也许)

但是,我需要汇总更改列表,例如[{"child[Id=child1].FirstName", "newName"},{"child[Id=child3].LastName", "newName"}(不一定是那个语法,而是一个变化字典)

【问题讨论】:

标签: c# mongodb


【解决方案1】:

据我所知,它可以通过一个限制来完成。如果我错了,请有人纠正我。这是更新命令:

db.Parents.update(
    {
        "_id": ObjectId("5cf7391a1c86292244c4424e"),
        "ChildrenA": {
            "$elemMatch": {
                "_id": ObjectId("5cf7391a1c86292244c4424c")
            }
        }
    },
    {
        "$set": {
            "ChildrenA.$.Property": "UPDATED",
            "PropertyA": "UPDATED",
            "ChildrenB.0.Property": "UPDATED",
            "ChildrenB.1.Property2": "UPDATED"
        }
    }
)

如您所见,您必须使用 $elemMatch 按 ID 定位嵌套子级。据我所知,您只能在单个更新命令中使用一个 $elemMatch(如果我错了,请纠正我)。

这是生成上述更新命令的 c# 代码。它使用的是MongoDB.Entities,这是一个便利库,我是它的作者。

using MongoDB.Entities;

namespace StackOverflow
{
    public class Program
    {
        public class Parent : Entity
        {
            public ChildA[] ChildrenA { get; set; }
            public string PropertyA { get; set; }
            public string PropertyB { get; set; }
            public ChildB[] ChildrenB { get; set; }
        }

        public class ChildA : Entity
        {
            public string Property { get; set; }
            public string Property2 { get; set; }
        }

        public class ChildB
        {
            public string Property { get; set; }
            public string Property2 { get; set; }
        }

        static void Main(string[] args)
        {
            new DB("test");

            var childA = new ChildA { Property = "update-me", Property2 = "leave-me-alone" };
            var childB = new ChildA { Property = "leave-alone", Property2 = "update-me" };
            childA.Save(); childB.Save();

            var parent = new Parent
            {
                ChildrenA = new[] { childA, childB },
                PropertyA = "update-me",
                PropertyB = "leave-me-alone",
                ChildrenB = new[] {
                new ChildB{ Property = "update-me", Property2 = "leave-me-alone"},
                new ChildB{ Property = "leave-alone", Property2 = "update-me"}
                }
            };
            parent.Save();

            DB.Update<Parent>()
              .Match(
                f => f.Eq(p => p.ID, parent.ID) &
                f.ElemMatch(
                    x => x.ChildrenA, 
                    x => x.ID == childA.ID))
              .Modify(x => x.ChildrenA[-1].Property, "UPDATED")
              .Modify(x => x.PropertyA, "UPDATED")
              .Modify(x => x.ChildrenB[0].Property, "UPDATED")
              .Modify(x => x.ChildrenB[1].Property2, "UPDATED")
              .Execute();
        }
    }
}

【讨论】:

  • 所以基本上,如果我知道各个项目的位置,我可以完全跳过使用 $ 并使用 .index 表示法进行更新?
  • @Chazt3n 是的,没错。如果您知道要在数组中更新的项目的索引位置,则可以在单个更新命令中批量处理所有更改。仅当您需要通过 id 或其他内容定位嵌套项目时才会出现此问题。当你需要这样做时,你必须为每个需要使用 $elemMatch 过滤的项目发出单独的更新命令(据我所知)。
  • 听起来我可以可靠地提取文档,通过代码进行所有搜索,并在我这样做时排队更改,我是否能够同时向同一个文档发送更新,或者这实际上是换一个?
  • @Chazt3n 带有$set operator 的更新命令只修改指定的字段。文档的其余部分保持不变。甚至我的库在内部使用 $set 运算符进行更新。
【解决方案2】:

您可以使用以下表单版本 3.4

db.Collection.findAndModify({
query: {  "_id" : "parent"},
update: { $set: {propertyA: "update-me" , "childrenA.$[childrenAelemnt].property" : "update-me" , "childrenB.$[childrenB2elemnt].property2" : "update-me"
},
arrayFilters: [ {"childrenAelemnt._id": "child1"},{"childrenBelemnt.property2": "leave-alone"} , {"childrenB2elemnt.property": "leave-alone"} ]})

如果 childrenB 数组中有 ID 字段。它会更容易一些,语法也会有点一致

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-22
    • 1970-01-01
    • 2016-11-18
    • 1970-01-01
    相关资源
    最近更新 更多