The mgo.Change type is specific to the Query.Apply method, which runs the MongoDB findAndModify command and does any of the supported modifications at once. The Upsert method, on the other hand, takes a modification document that will be directly provided to mgo/bson for marshalling. These modification documents have the same format whether you provide them via Query.Apply (in the Update
field of mgo.Change), or via the Collection.Upsert or Collection.Update methods.
So, the observed error is being caused because it's attempting to use mgo.Change
as a plain struct for inserting (in other words, a document with keys "returnnew", etc), which is definitely not what you want. The shell command you provided, for example, is equivalent to the straightforward translation with mgo:
type M map[string]interface{}
err := collection.Upsert(
M{
"_id": "98364_2013-12-11",
"ci": "16326",
"dt": "2013-12-11",
"zi": "98364",
},
M{
"$setOnInsert": M{"ci": "16326", "dt": "2013-12-11", "zi": "98364"},
"$inc": M{"test": 1},
},
)
This is still broken, though, but for a different reason. As the server mentioned in the error message, this is attempting to set the shard key a second time. Note that an upsert operation will make use of the fields provided in the query document, and merge both the query document and the modification document to create the final document for insertion. This means that the shard key fields in the $setOnInsert
document are redundant with the shard key fields in the query document.
I'll improve the documentation on that area to reduce the chances of people getting confused by the use of mgo.Change
. Sorry for the trouble.