4

In my Azure CosmosDb MongoApi I have JSON with an embed array of documents.

{
    "_id": ObjectId("5a95745df886842904b82f71"),
    "token": "value1",
    "channel": "value2",
    "urls":
    [
        {
            "url": "<url1>", 
            "interval": "<int>"
        },
        {
            "url": "<url2>"
            "interval": "<int>"
        }
    ]
}

I want to update "interval" field in a specific array element. Problem is when I use solutions like this or this, I end up with an exception:

MongoDB.Driver.MongoCommandException: Command findAndModify failed: Invalid BSON field name 'urls.$.interval'.

So, I decided to try running queries in Mongo Shell and got the same error:

{
    "nMatched": 0,
    "nUpserted": 0,
    "nModified": 0,
    "writeError": 
    {
        "code": 2,
        "errmsg": "Invalid BSON field name 'urls.$.interval'"
    }
}

Here is my C# code:

    var filterBuilder = Builders<User>.Filter;
    var filter = filterBuilder.Where(p => p.Token == model.Token && p.Channel == model.Channel && p.Urls.Any( u => u.Url == model.Url));
    var update = Builders<User>.Update.Set(p => p.Urls.ElementAt(-1).interval, 5);
    await _context.Users.FindOneAndUpdateAsync<User>(filter, update);

Here is my MongoDb shell request:

db.Users.update( {"urls.interval": 60}, {$set: {"urls.$.interval": 30}} ); 

My question is what is causing this exception and how can I avoid it?

2
  • Did you try db.Users.update( {"Urls.interval": 60}, {$set: {"Urls.$.interval": 30}} ); ? Commented Feb 27, 2018 at 16:39
  • @mickl Yep, sorry, formatting error, in my JSON schema I have "urls" lower case. I'll update the question right away. Commented Feb 27, 2018 at 17:39

1 Answer 1

1

Positional operator is not currently supported by Cosmos DB. Please use the following workaround: iterate over documents and array elements on the client side, change the required element and issue an update on the document with new array:   For example, assuming you have a collection users of following elements:

{ 
    "_id" : ObjectId("59d6b719708b990d6c9b3aca"), 
    "tags" : [
        {
            "id" : 1, 
            "value" : "11"
        }, 
        {
            "id" : 2, 
            "value" : "22"
        }, 
        {
            "id" : 3, 
            "value" : "32"
        }
    ]
}
 

…you can issue the following command to get one of the elements (with id=1 in this case) updated:  

db.users.find().forEach( 
        function(user) 
        { 
         user.tags.forEach( 
         function(tag) 
         {
               if (tag.id=="1")
               {
                       tag.value = "Updated!";                          
                       db.users.updateOne({_id : user._id}, {$set: {"tags": user.tags}});
               }
        }
        );
       }  
);

You can adjust the condition in if() with even finer granularity than positional operator allows.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot it helped!

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.