不了解mongoDB Update在Go中的工作原理



我正在尝试为Go结构实现MongoDB更新。简单来说,它看起来像这样:

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

这将生成错误消息,指示该值未更新。我错过了什么?

我知道只更新一个字段是可能的,但考虑到这是在数据层中,在数据层之上的代码对MongoDB没有任何了解,这将是一个很难用通用方式实现的问题。也就是说,我真的需要对Go对象进行任何更新,然后更新后备存储中对象的副本。我想我可以检索对象并手动进行"diff",构建一个"$set"文档,但这似乎不是每次更新都添加一个检索会非常有效。

编辑:尝试删除的"_id"地图

我已经尝试将代码修改为以下内容:

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

并且仍然接收到相同的结果(Expected cherry, got apple)。请注意,对UpdateId()的调用没有返回错误。

问题是我使用了错误的字段作为键。我已经将"Id"映射为"_Id",但随后要求MongoDB使用Go属性名称而不是名称来查找记录。这是正确的:

package testmgo
import (
    mgo "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
    "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"
    if err := col.UpdateId(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)
    }
}

最新更新