Принудительно отображать типы с помощью mgo

Член _id больше не сопоставляется с типом ObjectId, когда его тип является производным только от bson.ObjectId:

import (
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)

type CustomId bson.ObjectId

type Foo struct {
    ID1    CustomId `bson:"_id"` // broken
    ID2    bson.ObjectId         // mapped as expected
}


func main() {
    session, _ := mgo.Dial("127.0.0.1")
    coll := session.DB("mgodemo").C("foocoll")

    doc := Foo{
        CustomId(bson.NewObjectId()),
        bson.NewObjectId(),
    }

    coll.Insert(doc)
}

_Id должен был быть ObjectId в Mongo. Но оказывается, что строка была выбрана:

Монго Шелл:

> db.foocoll.findOne()
{ "_id" : "XvMn]K� �\f:�", "id2" : ObjectId("58764d6e5d4be120fa0c3ab1") }  // id2 is OK ...

> typeof db.foocoll.findOne()._id
string  // OOps. Should be ObjectId !

Это может быть предназначено, так как сам bson.ObjectId является производным от строки. Но здесь это плохо для нас.

Можем ли мы сказать mgo отобразить _id в ObjectId в базе данных?

2 ответа

Решение

Используйте интерфейсы Setter и Getter для управления представлением в монго:

type CustomId bson.ObjectId

func (id *CustomId) SetBSON(raw bson.Raw) error {
   var v bson.ObjectId
   err := raw.Unmarshal(&v)
   *id = CustomId(v)
   return err
}
func (id CustomId) GetBSON() (interface{}, error) {
   return bson.ObjectId(id), nil
}

Когда вы делаете это:

type CustomId bson.ObjectId

Вы создаете новый тип и mgo пакет не увидит / не распознает как bson.ObjectId больше (тип bson.ObjectId является "жестко закодированным" в пакете bson). Новый тип будет иметь 0 методов.

Я бы просто придерживался bson.ObjectId, Но если вам все еще нужен пользовательский тип идентификатора, вы можете использовать встраивание при создании CustomId: вставьте значение типа bson.ObjectIdи использовать inline Бсон флаг для ID1 поле:

type CustomId struct {
    bson.ObjectId `bson:"_id"`
}

type Foo struct {
    ID1 CustomId      `bson:",inline"`
    ID2 bson.ObjectId 
}

Используй это:

doc := Foo{
    CustomId{bson.NewObjectId()},
    bson.NewObjectId(),
}

Это имеет то преимущество, что CustomId будет иметь все методы bson.ObjectId имеет, и вы можете добавить новые и "переопределить" существующие методы.

Другой вариант будет использовать тип интерфейса (например, interface{}) для тебя CustomIdс его использованием было бы намного "проще":

type CustomId interface{}

type Foo struct {
    ID1 CustomId      `bson:"_id"`
    ID2 bson.ObjectId // mapped as expected
}

Используй это:

doc := Foo{
    bson.NewObjectId(),
    bson.NewObjectId(),
}

Конечно, идя по этому пути, вы должны использовать утверждение типа, если вам нужен доступ к bson.ObjectId из CustomId,

Другие вопросы по тегам