4

I'm having trouble finding the right syntax to replace an array of objects nested several levels deep within a collection. My preference is to just update the individual properties, but since reading the link below, it seems replacing the whole array is the best bet.

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

So I have the following classes as an example:

public class Parent
    {
        public ObjectId _id { get; set; }
        public string Firstname { get; set; }
        public string Lastname { get; set; }
        public Collection<Child> Children { get; set; }
    }

    public class Child
    {
        public ObjectId _id { get; set; }
        public string Firstname { get; set; }
        public string Lastname { get; set; }
        public Collection<Pet> Pets { get; set; }
    }

    public class Pet
    {
        public string Name { get; set; }
    }

Using the following code I create a Parent, add some Children, and add a Pet to one of the children.

// Construct Objects
Parent parent = new Parent() { _id = new ObjectId("4f979621682dbc1a8cefecb1") };

Collection<Child> children = new Collection<Child>();
Collection<Pet> pets = new Collection<Pet>();

children.Add(new Child() 
    { _id = new ObjectId("4f979621682dbc1a8cefecaf"), 
      Firstname = "Child", 
      Lastname = "One" });
children.Add(new Child() 
    { _id = new ObjectId("4f979621682dbc1a8cefecb0"), 
      Firstname = "Child", 
      Lastname = "Two" });
pets.Add(new Pet() { Name = "Fishy" });

parent.Children = children;
parent.Children[0].Pets = pets;

// Connect to Mongo
var server = MongoServer.Create("mongodb://localhost/?safe=true");
var db = server.GetDatabase("test");

// Insert into parent collection
MongoCollection<Parent> parents;
parents = db.GetCollection<Parent>("parents");
parents.Insert<Parent>(parent, MongoDB.Driver.SafeMode.True);

This successfully inserts the objects, generating the following JSON result:

{   "_id" : ObjectId("4f979621682dbc1a8cefecb1"),
    "Firstname" : null,
    "Lastname" : null,
    "Children" : 
    [
        {
            "_id" : ObjectId("4f979621682dbc1a8cefecaf"),
            "Firstname" : "Child",
            "Lastname" : "One",
            "Pets" : 
            [
                {
                    "Name" : "Fishy"
                }
            ]
        },
        {
            "_id" : ObjectId("4f979621682dbc1a8cefecb0"),
            "Firstname" : "Child",
            "Lastname" : "Two",
            "Pets" : null
        }
    ]
}

Updating individual document elements also seems to be a trivial process, and works successfully with the following code.

// Change children's name
var query = new QueryDocument { { "Children._id", new ObjectId("4f979621682dbc1a8cefecaf") } };
var update = Update.Set("Children.$.Firstname", "Something");
parents.Update(query, update);

Now the issue I can't work out is how to replace the Pets array. The following code doesn't compile as Update.Set doesn't accept a Collection.

// Change pets information
pets[0].Name = "Fishy2"; // change to pet
pets.Add(new Pet() { Name = "Doggy" }); // add new pet

query = new QueryDocument { { "Children._id", new ObjectId("4f979621682dbc1a8cefecaf") } };
update = Update.Set("Children.$.Pets", pets);
parents.Update(query, update);

So what's the best process that would enable me to update the details in the Pets array?

2
  • 1
    Why on earth are you using a bloody array to do this. It would be fair easier with a Generic Collection! Commented Jun 20, 2012 at 13:19
  • 1
    @Ramhound: he is using a generic collection. To what are you referring? Commented Jun 20, 2012 at 18:30

2 Answers 2

2

Here is the code you are looking for: You'll need to pass in a BsonArray to the Update.Set value. To create that array, you'll need to wrap each of the "pets" in a BsonDocumentWrapper so the serialization library knows how to serialize them appropriately.

var query = new QueryDocument { { "Children._id", new ObjectId("4f979621682dbc1a8cefecaf") } };
var petDocuments = BsonDocumentWrapper.CreateMultiple(pets);
var petArray = new BsonArray(petDocuments);
var update = Update.Set("Children.$.Pets", petArray);
parents.Update(query, update);
Sign up to request clarification or add additional context in comments.

1 Comment

Brilliant. Thanks Craig. Works a treat.
0
> db.Questions.find().pretty()
{
        "Answers" : [
                {
                        "_id" : ObjectId("52ae4946e1df9e1b10e1f6e1"),
                        "Text" : "ans",
                        "Comments" : [ ]
                }
        ],
        "CreatedDate" : ISODate("2013-12-16T00:28:47.790Z"),
        "QuestionText" : "test",
        "QuestionTitle" : "test",
        "Tag" : "test",
        "UserID" : "singleuserid_777",
        "_id" : ObjectId("52ae493fe1df9e1b10e1f6e0")
}
>

Now if I need to update Comments array in Answers array in Questions collection then my C#.Net code will be

  base.GetContext.Collection.Find(Query.EQ("Answers._id", ObjectId.Parse(Id))).Collection.Update(Query.EQ("Answers._id", ObjectId.Parse(Id)),MongoDB.Driver.Builders.Update.PushWrapped("Answers.$.Comments", comm));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.