Question

I am imagining foo is doing update on the third comment, comments.2.value, while bar is $pull-ing, removing the first comment.

If foo finishes first, then the third comment is updated successfully, since the index is still correct.

But if bar finishes first, then the index has changed, and foo's comments.2.value would affect not the third comment anymore.

Is this scenario possible, and if it is, i wonder whether there are common solutions for array element updates and racing condition ?

Thank you !

Was it helpful?

Solution

The situation that you described is theoretically possible if multiple applications are accessing the database simultaneously. For this reason, it is best, if possible, to give each member of the array some unique identifier, rather than accessing elements in the array by position.

For example,

> db.myComments.save({_id:1,
comments:[
{cid:1, author:"Marc", comment:"Marc's Comment"}, 
{cid:2, author:"Mike", comment:"Mike's Comment"}, 
{cid:3, author:"Barrie", comment:"Barrie's Comment"}
]})

If we want to modify Mike's Comment, but we don't necessarily know that it will appear second in the array, we can update it like so:

> db.myComments.update({_id:1, "comments.cid":2}, {$set:{"comments.$.comment":"Mike's NEW Comment"}})
> db.myComments.find().pretty()
{
    "_id" : 1,
    "comments" : [
        {
            "cid" : 1,
            "author" : "Marc",
            "comment" : "Marc's Comment"
        },
        {
            "author" : "Mike",
            "cid" : 2,
            "comment" : "Mike's NEW Comment"
        },
        {
            "cid" : 3,
            "author" : "Barrie",
            "comment" : "Barrie's Comment"
        }
    ]
}

We could even change the entire sub-document, like so:

> db.myComments.update({_id:1, "comments.cid":2}, {$set:{"comments.$":{cid:4, author:"someone else", comment:"A completely new comment!"}}})
> db.myComments.find().pretty()
{
    "_id" : 1,
    "comments" : [
        {
            "cid" : 1,
            "author" : "Marc",
            "comment" : "Marc's Comment"
        },
        {
            "cid" : 4,
            "author" : "someone else",
            "comment" : "A completely new comment!"
        },
        {
            "cid" : 3,
            "author" : "Barrie",
            "comment" : "Barrie's Comment"
        }
    ]
}

The query document will find the first value in the array that matches, and the "$" in the update document references that position.

More information on the "$" operator may be found in the "The $ positional operator" section of the "Updating" documentation. http://www.mongodb.org/display/DOCS/Updating#Updating-The%24positionaloperator

Hopefully this will give you an idea of how your application can modify values in an array without referencing their position. Good luck!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top