2017-01-11 12 views
2

членом _id не отображаются на тип ObjectId больше, когда его тип только получен из bson.ObjectId:Enforce отображения типа с МдО

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. Но оказывается, что строка была выбрана:

Монго 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 сам является производным от строки. Но здесь это плохо для нас.

Можем ли мы сказать mgo, чтобы сопоставить _id с ObjectId в базе данных?

ответ

3

Используйте интерфейсы 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 
} 
+0

Ницца. Отредактировано, чтобы сделать его компилируемым. – icza

1

Когда вы сделаете это:

type CustomId bson.ObjectId 

Вы создаете новый тип и mgo пакет не будет увидеть/распознать его как bson.ObjectId больше (тип bson.ObjectId является «жёстко» в пакете BSON). Новый тип будет иметь 0 методов.

Я бы просто придерживался bson.ObjectId. Но если вы все еще хотите пользовательский типа ID, вы можете использовать вложение при создании CustomId: встраивать значение типа bson.ObjectId, и использовать флаг в inline BSON для 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(), 
} 

Конечно , идя по этой дороге, вы должны использовать type assertion, если вам нужно получить доступ к обернутому bson.ObjectId из CustomId.

+0

С вложением, я вижу недостаток, что Foo должен знать CustomId требует, чтобы быть встраиваемыми. Все еще умный и работает хорошо. – shful