With an empty data set, running an update operation against the server to perform a document replacement uses the _id in the query to initialize it:
local:PRIMARY> db.test.update({$and:[{_id: 1000}]}, {foo:10000}, {upsert:true})
WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : 1000 })
local:PRIMARY> db.test.find()
{{
{ "_id" : 1000, "foo" : 10000 }}}
However doing the equivalent operation through the stitch library doesn't seem to take into account the query when initializing the upserted doc in the same manner. Here is a failing test case:
t.Run("upsert with a compound expression query should initialize upserted doc correctly with replacement", func(t *testing.T) { matcher, err := stitchmongo.NewMatcher(bson.D{{"$and", []interface{}{ bson.D{{"_id", 1000}}, }}}) u.So(t, err, gc.ShouldBeNil) defer matcher.Close() updater, err := stitchmongo.NewUpdater( bson.D{{"z", 3}}, matcher, ) u.So(t, err, gc.ShouldBeNil) defer updater.Close() result, err := updater.ApplyUpsert() u.So(t, err, gc.ShouldBeNil) u.So(t, result.UpdatedDocument, gc.ShouldResemble, bson.D{{"_id", 1000}, {"z", 3}}) u.So(t, result.IsReplacement, gc.ShouldBeTrue) })
Interestignly though the same operation does work equivalently to the server when the update uses $ modifiers instead. For example, the following test passes:
t.Run("upsert with a compound expression query should initialize upserted doc correctly with update modifiers", func(t *testing.T) { matcher, err := stitchmongo.NewMatcher(bson.D{{"$and", []interface{}{ bson.D{{"_id", 1000}}, bson.D{{"x", 50}}, }}}) u.So(t, err, gc.ShouldBeNil) defer matcher.Close() updater, err := stitchmongo.NewUpdater( bson.D{{"$set", bson.D{{"z", 3}}}}, matcher, ) u.So(t, err, gc.ShouldBeNil) defer updater.Close() result, err := updater.ApplyUpsert() u.So(t, err, gc.ShouldBeNil) u.So(t, result.UpdatedDocument, gc.ShouldResemble, bson.D{{"_id", 1000}, {"x", 50}, {"z", 3}}) u.So(t, result.IsReplacement, gc.ShouldBeFalse) })