|
No, this isn't about insert/upsert, where conceptually the collision is due to a failure of the server to implement the abstraction of serialized operations. In fact I think the new option should be considered incompatible with upsert (i.e., you shouldn't be allowed to set both). Here's an example that may clear things up:
> db.tag.ensureIndex({user:1,object:1,tag:1},{unique:true})
|
{
|
"createdCollectionAutomatically" : true,
|
"numIndexesBefore" : 1,
|
"numIndexesAfter" : 2,
|
"ok" : 1
|
}
|
> var uid = new ObjectId();
|
> db.tag.insert({user:uid, object:34, tag:"star"})
|
WriteResult({ "nInserted" : 1 })
|
> db.tag.insert({user:uid, object:35, tag:"star"})
|
WriteResult({ "nInserted" : 1 })
|
> db.tag.insert({user:uid, object:35, tag:"spam"})
|
WriteResult({ "nInserted" : 1 })
|
> db.tag.find()
|
{ "_id" : ObjectId("564e599bc04934e40e8716f5"), "user" : ObjectId("564e5994c04934e40e8716f4"), "object" : 34, "tag" : "star" }
|
{ "_id" : ObjectId("564e599fc04934e40e8716f6"), "user" : ObjectId("564e5994c04934e40e8716f4"), "object" : 35, "tag" : "star" }
|
{ "_id" : ObjectId("564e59aac04934e40e8716f7"), "user" : ObjectId("564e5994c04934e40e8716f4"), "object" : 35, "tag" : "spam" }
|
> db.tag.update({object:35}, {$set:{object:34}}, {multi:true})
|
WriteResult({
|
"nMatched" : 0,
|
"nUpserted" : 0,
|
"nModified" : 0,
|
"writeError" : {
|
"code" : 11000,
|
"errmsg" : "E11000 duplicate key error index: test.tag.$user_1_object_1_tag_1 dup key: { : ObjectId('564e5994c04934e40e8716f4'), : 34.0, : \"star\" }"
|
}
|
})
|
At this point the application has a bunch of work to do to figure out what operations are going to be needed to achieve the desired result without creating any duplicate keys. Something like:
> db.tag.remove({user:uid, object:35, tag:"star"})
|
WriteResult({ "nRemoved" : 1 })
|
> db.tag.update({object:35}, {$set:{object:34}}, {multi:true})
|
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
|
Imagine instead being able to just do this:
> db.tag.update({object:35}, {$set:{object:34}}, {multi:true, dropDups:true})
|
WriteResult({ "nMatched" : 2, "nUpserted" : 0, "nModified" : 1, "nRemoved" : 1 })
|
> db.tag.find()
|
{ "_id" : ObjectId("564e599bc04934e40e8716f5"), "user" : ObjectId("564e5994c04934e40e8716f4"), "object" : 34, "tag" : "star" }
|
{ "_id" : ObjectId("564e59aac04934e40e8716f7"), "user" : ObjectId("564e5994c04934e40e8716f4"), "object" : 34, "tag" : "spam" }
|
|