Yes and No, really. Consider the following array:
{ array: [ { a: "a", b: "b" }, { a:"a", b:"c" } ] }
So you could $pull the second element from here with the following statement:
db.collection.update({}, {$pull: { array: { a: "a", b: "b"} } })
And that would remove the matching document. But if did the same thing on this array:
{ array: [ { a: "a", b: "b" }, { a: "a", b:"c", c: "c" }, { a:"a", b:"c" } ] }
Then this would be the result:
{ array: [ { a: "a", b: "b" }] }
So the query matched two of the documents in the array, and pulled them both.
Unfortunately the seemingly obvious:
db.collection.update({}, {$pull: { array: { $elemMatch:{ a: "a", b: "b" } }} })
Just wont work. Which is a pity. In the too hard basket to parse at this time.
So the moral of the story is, if you really concerned about concurrency and race conditions for this type of update, .find()
the matching element first, then update()
with a statement that matches the whole document, as long as it will not also partially match another document in the array.
If you cannot do that, then the method you describe in the question is currently the only way.
There is a JIRA issue on this, but it is not exactly terribly popular.