Para responder a la "Mi verdadera pregunta:¿Cómo puedo personalizar el comportamiento de mgo antes de la inserción? ":puede personalizar la ordenación de bson definiendo bson Getter al modelo
Para ilustrar cómo funciona, simplifiquemos el modelo para evitar documentos anidados:
type Game struct {
ID int `bson:"_id"`
Name string
Stats [] float64
}
Con newGame de la siguiente manera:
newGame := Game{
ID: 1,
Name: "foo",
Stats: []{5.0}
}
La actualización col.UpsertId(newGame.ID, newGame)
por defecto marshals newGame
en JSON, produciendo una consulta mongo como:
update({_id:1}, {name: "foo", stats: [5]}, {upsert: true});
Para hacer uso de $set
, $push
etc., puede definir un captador de bson personalizado. Por ejemplo
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
}
Entonces la actualización col.UpsertId(newGame.ID, newGame)
producirá una consulta mongodb
update({_id:1}, {$set: {name: "foo"}, $push: {stats: {$each: [5]}}}, {upsert: true});
Para que quede muy claro:el serializador personalizado se usará en todas las consultas de mgo, por lo que probablemente no desee definirlo directamente en el modelo, sino en su derivado para usar solo en operaciones 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})