Не понимаю, как работает обновление mongoDB в Go

Я пытаюсь реализовать обновление MongoDB для структуры Go. В упрощенном виде это выглядит примерно так:

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() не возвращает ошибку.


person Scott Deerwester    schedule 06.05.2016    source источник
comment
Вы пытаетесь обновить поле _id с помощью этой инструкции col.Update(obj1.Id, bson.M{"$set": &obj1}), что невозможно в MongoDB, отсюда и ошибка. Вам нужно создать объект, который не имеет поля _id для использования в вашем выражении $set.   -  person chridam    schedule 06.05.2016
comment
Я не вижу, как это сделать со структурой. Самое близкое, что я мог сделать, это маршалировать его в BSON, затем разбирать, затем на карту, а затем удалять запись _id с карты. Есть лучший способ сделать это?   -  person Scott Deerwester    schedule 06.05.2016


Ответы (1)


Проблема заключалась в том, что я использовал неправильное поле в качестве ключа. Я сопоставил «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)
    }
}
person Scott Deerwester    schedule 07.05.2016