Enforce a type mapping with mgo

懵懂的女人 提交于 2019-12-13 16:54:01

问题


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:


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:


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.



来源:https://stackoverflow.com/questions/41595577/enforce-a-type-mapping-with-mgo

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!