4

I have a document in MongoDB that looks like that:

{
    "Id":"123",
    "Product": "test",
    "Tags":[
        {
            "Name": "name",
            "Categories": [
                {
                    //item
                },
                {
                    //item
                }
            ]
        },
        {
            "Name": "name",
            "Categories": [
                {
                    //item
                },
                {
                    //item
                }
            ]
        }
    ]
}

Now, I need to add a new Item and it needs to be added to all of the categories of the Tags element of that Product by its Id. For example, when I'll insert Item 3 the document should look like this:

{
    "Id":"123",
    "Product": "test",
    "Tags":[
        {
            "Name": "name",
            "Categories": [
                {
                    //item 1
                },
                {
                    //item 2
                },
                {
                    //item 3
                }
            ]
        },
        {
            "Name": "name",
            "Categories": [
                {
                    //item 1
                },
                {
                    //item 2
                },
                {
                    //item 3
                }
            ]
        }
    ]
}

and same goes for removing an item, it needs to be removed from all of the categories as well. Is there a way to do that with the C# MongoDB Driver without pulling the object and "manually" updating them?

1 Answer 1

11

You can try something like below in 2.5 driver with 3.6 version.

Finds the document with filter criteria and update which includes new positional identifier to update multiple elements in array inside UpdateOne method.

$[] updates all the Tags arrays to include new item in all Categories array. It acts as a placeholder for updating all elements in array.

Push

var filter = Builders<Product>.Filter.Eq("Id", "123");
var update = Builders<Product>.Update.Push("Tags.$[].Categories", "Item 3");
var result = collection.UpdateOne(filter, update);

Pull

var filter = Builders<Product>.Filter.Eq("Id", "123");
var update = Builders<Product>.Update.Pull("Tags.$[].Categories", "Item 3");
var result = collection.UpdateOne(filter, update);

Additional Information:

You can set the ArrayFilters options in UpdateOptions for applying query criteria on nested array to control what elements to update.

For example to update all the Categories in Tags array where each tag has Name name.

var filter = Builders<Product>.Filter.Eq("Id", "123");
var update = Builders<Product>.Update.Push("Tags.$[t].Categories", "Item 3");
var arrayFilters = new List<ArrayFilterDefinition>{ new ArrayFilterDefinition(new BsonDocument("t.Name", "name")) };
var updateOptions = new UpdateOptions({ArrayFilters = arrayFilters});
var result = collection.UpdateOne(filter, update, updateOptions);
Sign up to request clarification or add additional context in comments.

9 Comments

I'm getting this error on the Push solution: "A write operation resulted in an error.\r\n cannot use the part (Tags of Tags.$[].Categories) to traverse the element
It looks like you are not on the latest 3.6 version. Execute db.version() in shell to check the version.
I&#39;ve already checked it, version 3.6.1... I run it in Robo mongo.
Didn't get a chance to test c# code but I was able to run queries in shell for the sample data provided. Not sure where the error is. Try looking at the data you are trying to update and run queries in shell. May be some of your documents are missing Categories or Tags and both are type of arrays. Try db.collection_name.find({"Id":"123"}, {"$push":{"Tags.$[].Categories":"Item 3"}}); in shell.
I copy pasted your query into my Robo Mongo query editor and it gives this error: Error: error: { "ok" : 0, "errmsg" : "Unsupported projection option: $push: { Tags.$[].Categories: \"Item 3\" }", "code" : 2, "codeName" : "BadValue" }
|

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.