Принудительно отображать типы с помощью 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
,