За да отговорите на „Моят истински въпрос:Как мога да персонализирам поведението на mgo преди upsert? " - можете да персонализирате bson marshalling, като дефинирате bson Getter към модела.
За да илюстрираме как работи, нека опростим модела, за да избегнем вложени документи:
type Game struct {
ID int `bson:"_id"`
Name string
Stats [] float64
}
С newGame както следва:
newGame := Game{
ID: 1,
Name: "foo",
Stats: []{5.0}
}
Актуализацията col.UpsertId(newGame.ID, newGame)
по подразбиране маршали newGame
в JSON, създавайки mongo заявка като:
update({_id:1}, {name: "foo", stats: [5]}, {upsert: true});
За да използвате $set
, $push
и т.н., можете да дефинирате персонализиран инструмент за получаване на bson. Напр.
func (g Game) GetBSON() (interface{}, error) {
return bson.M{
"$set": bson.M{"name": g.Name},
"$push": bson.M{"stats": bson.M{"$each": g.Stats}},
}, nil
}
Така че актуализацията col.UpsertId(newGame.ID, newGame)
ще генерира mongodb заявка
update({_id:1}, {$set: {name: "foo"}, $push: {stats: {$each: [5]}}}, {upsert: true});
За да стане кристално ясно – персонализираният маршалер ще се използва във всички mgo заявки, така че вероятно не искате да го дефинирате директно към модела, а към негово производно, за да използвате само в upsert операции:
type UpdatedGame struct {
Game
}
func (g UpdatedGame) GetBSON() (interface{}, error) {
return bson.M{....}
}
.....
newGame := Game{
ID: 1,
Name: "foo",
Stats: []{5.0}
}
col.UpsertId(newGame.ID, UpdatedGame{newGame})