Search code examples
mongodbgobsonmgo

Enforce a type mapping with mgo


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 ?


Solution

  • 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
    }