MongoDb更新同一阵列中的多个特定嵌入式文档

时间:2019-05-11 15:34:59

标签: c# mongodb

我有一个用例,其中视图允许用户更新多个对象并立即提交,如何使这个原子化?

{_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"}(不一定是该语法,而是更改字典)

2 个答案:

答案 0 :(得分: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();
        }
    }
}

答案 1 :(得分:1)

您可以使用以下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字段。它将变得更容易,语法也不会保持一致