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)
})