当_id成员的类型仅从bson.ObjectId派生时,它不会映射到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 在蒙戈。 但事实证明选择了 string :
Mongo Shell:
> 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 本身是从 string 派生的。但是在这里,这对我们不利。
我们可以告诉mgo将_id映射到数据库中的ObjectId吗?
答案 0 :(得分:3)
使用Setter和Getter接口控制mongo中的表示形式:
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
}
答案 1 :(得分:2)
执行此操作时:
type CustomId bson.ObjectId
您正在创建一个新类型,mgo
包不会再将其视为/ bson.ObjectId
(类型bson.ObjectId
是"硬编码"在bson中包)。新类型将有0个方法。
我会坚持bson.ObjectId
。但是,如果您仍需要自定义ID类型,则可以在创建CustomId
时使用嵌入:嵌入类型为bson.ObjectId
的值,并使用inline
bson标志用于{{1} } field:
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
,则必须使用type assertion。