One of the benefits of being a TA for M102 course is that you get to learn even more by answering questions. Because some questions are fascinating.
Yesterday we had a very interesting case that puzzled even those folks who are usually able to answer anything in the forum. There was some virtual head scratching (or at least I’m imagining it), and we decided to ask the 10gen team if they can shed some light on this.
Here’s the scenario, where we are starting with an empty collection:
db.test.update({_id : "Jane"}, {"count" : 1}, true)
db.test.update({_id : "Jane2"}, {$set: {"count" : 1}}, true)
db.test.find()
{ "_id" : ObjectId("510aa62cbb530b24318c93d4"), "count" : 1 }
{ "_id" : "Jane2", "count" : 1 }
As we see, in both update statements, the “upsert” option is set to true.
The result of the first statement is a document with an _id field assigned by default by MongoDB, even though we specified _id:”Jane”.
However, the result of the second statement is the document with the _id that we specified – so it’s a different outcome when we use “$set” operation.
And here’s the explanation (from MongoDB docs):
If the argument includes only field and value pairs, the new document contains the fields and values specified in the argument. If the argument includes only update operators, the new document contains the fields and values from argument with the operations from the argument applied.
Link: http://docs.mongodb.org/manual/applications/update/
Then Andrew also explained in the discussion forum:
The behavior of the update operator depends on what is the second positional document. If you put in set operator or push operator, then the db will insert a document that has both the fields that are set in the selector and is the result of applying your pushes and sets.
So this behavior is expected, but still makes a very interesting case. Live and learn, my friends!