I'm trying to implement a MongoDB update for a Go struct. Stripped down to essentials, it looks something like this:
type MyStruct struct {
Id bson.ObjectId `bson:"_id"`
Fruit string `bson:"fruit"`
}
func TestUpdate(t *testing.T) {
obj1 := MyStruct{Id: bson.NewObjectId(),Fruit: "apple"}
var obj2 MyStruct
session, _ := mgo.Dial("whatever")
col := session.DB("test").C("collection")
col.Insert(&obj1)
obj1.Fruit = "cherry"
if err := col.Update(obj1.Id, bson.M{"$set": &obj1}); err != nil {
t.Errorf(err.Error())
}
if err := col.Find(bson.M{"Id": obj1.Id}).One(&obj2); err != nil {
t.Errorf(err.Error())
}
if obj1.Fruit != obj2.Fruit {
t.Errorf("Expected %s, got %s", obj1.Fruit, obj2.Fruit)
}
}
This generates the error message, indicating that the value wasn't updated. What am I missing?
I understand that just updating one field is possible, but given that this is in a data layer, above which the code doesn't have any knowledge of MongoDB, that would be challenging to implement in a general way. I.e. I really need to make any updates to the Go object, and then update the copy of the object in the backing store. I suppose that I could retrieve the object and do a "diff" manually, constructing a "$set" document, but that doesn't seem like adding a retrieval every time I do an update would be very efficient.
Edit: Trying a map with "_id" deleted
I've tried amending the code to the following:
package testmgo
import (
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"github.com/fatih/structs"
"testing"
)
type MyStruct struct {
Id bson.ObjectId `bson:"_id"`
Fruit string `bson:"fruit"`
}
func TestUpdate(t *testing.T) {
obj1 := MyStruct{Id: bson.NewObjectId(),Fruit: "apple"}
var obj2 MyStruct
session, _ := mgo.Dial("localhost")
col := session.DB("test").C("collection")
col.Insert(&obj1)
obj1.Fruit = "cherry"
omap := structs.Map(&obj1)
delete(omap, "_id")
if err := col.UpdateId(obj1.Id, bson.M{"$set": bson.M(omap)}); err != nil {
t.Errorf(err.Error())
}
if err := col.Find(bson.M{"Id": obj1.Id}).One(&obj2); err != nil {
t.Errorf(err.Error())
}
if obj1.Fruit != obj2.Fruit {
t.Errorf("Expected %s, got %s", obj1.Fruit, obj2.Fruit)
}
}
and am still receiving the same results (Expected cherry, got apple
). Note that the call to UpdateId() is not returning an error.