Per rispondere alla "La mia vera domanda:come posso personalizzare il comportamento di mgo prima dell'upsert? " - puoi personalizzare il marshalling di bson definendo bson Getter al modello.
Per illustrare come funziona, semplifichiamo il modello per evitare documenti nidificati:
type Game struct {
ID int `bson:"_id"`
Name string
Stats [] float64
}
Con newGame come segue:
newGame := Game{
ID: 1,
Name: "foo",
Stats: []{5.0}
}
L'aggiornamento col.UpsertId(newGame.ID, newGame)
per impostazione predefinita esegue il marshalling di newGame
in JSON, producendo query mongo come:
update({_id:1}, {name: "foo", stats: [5]}, {upsert: true});
Per utilizzare $set
, $push
ecc, puoi definire un getter bson personalizzato. Es.
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
}
Quindi l'aggiornamento col.UpsertId(newGame.ID, newGame)
produrrà una query mongodb
update({_id:1}, {$set: {name: "foo"}, $push: {stats: {$each: [5]}}}, {upsert: true});
Per chiarire, il marshaler personalizzato verrà utilizzato in tutte le query mgo, quindi probabilmente non lo si desidera definire direttamente nel modello, ma nel suo derivato da utilizzare solo nelle operazioni di 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})