英文:
Enforce a type mapping with 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应该在Mongo中是一个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吗?
英文:
An _id member is not mapped to type ObjectId anymore, when its type is only derived from 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)
}
The _id should have been an ObjectId in Mongo.
But it turns out that string was choosen:
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 !
This may be intended, since bson.ObjectId itself is derived from string. But here, it's bad for us.
Can we tell mgo to map the _id to ObjectId in the Database ?
答案1
得分: 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
}
英文:
Use the Setter and Getter interfaces to control the representation in 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
}
答案2
得分: 2
当你这样做时:
type CustomId bson.ObjectId
你创建了一个新的类型,mgo
包将不再将其识别为bson.ObjectId
(bson.ObjectId
类型在bson
包中是“硬编码”的)。这个新类型将没有任何方法。
我建议你仍然使用bson.ObjectId
。但是如果你仍然想要一个自定义的ID类型,你可以在创建CustomId
时使用嵌入:嵌入一个类型为bson.ObjectId
的值,并为ID1
字段使用inline
bson标记:
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
的所有方法,你还可以添加新的方法并“覆盖”现有的方法。
另一种选择是为你的CustomId
使用接口类型(例如interface{}
),这样使用起来会更加“简单”:
type CustomId interface{}
type Foo struct {
ID1 CustomId `bson:"_id"`
ID2 bson.ObjectId // 正常映射
}
使用它:
doc := Foo{
bson.NewObjectId(),
bson.NewObjectId(),
}
当然,如果你需要访问CustomId
的包装bson.ObjectId
,你需要使用类型断言。
英文:
When you do this:
type CustomId bson.ObjectId
You are creating a new type and the mgo
package will not see / recognize it as bson.ObjectId
anymore (the type bson.ObjectId
is "hardcoded" in the bson package). The new type will have 0 methods.
I would just stick to bson.ObjectId
. But if you still want a custom ID type, you may use embedding when creating your CustomId
: embed a value of type bson.ObjectId
, and use the inline
bson flag for the ID1
field:
type CustomId struct {
bson.ObjectId `bson:"_id"`
}
type Foo struct {
ID1 CustomId `bson:",inline"`
ID2 bson.ObjectId
}
Using it:
doc := Foo{
CustomId{bson.NewObjectId()},
bson.NewObjectId(),
}
This has the advantage that CustomId
will have all the methods bson.ObjectId
has, and you can add new ones and "override" existing methods.
Another option would be to use an interface type (e.g. interface{}
) for your CustomId
, using it would be a lot "simpler":
type CustomId interface{}
type Foo struct {
ID1 CustomId `bson:"_id"`
ID2 bson.ObjectId // mapped as expected
}
Using it:
doc := Foo{
bson.NewObjectId(),
bson.NewObjectId(),
}
Of course, going down this road, you have to use type assertion, should you need to access the wrapped bson.ObjectId
of the CustomId
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论