前提
GoのMongoDBクライアントとしてgo-mgo/mgoを使用している。
各構造体のfieldの型としてgo-mgo/mgoのbson.ObjectIdを埋め込んでいる。
go-mgo/mgoを使用する際には、bson.Mやbson.Dなども使用している。
go-mgo/mgoはメンテナンスが終わっている。
やりたいこと
go-mgo/mgoからmongodb/mongo-go-driverに移行する。
それに伴い、bson.ObjectIdをbson.ObjectIDに移行する。
bson.Mやbson.Dなどをmongodb/mongo-go-driver側のものに移行する。
考慮すること
直接mongodb/mongo-go-driver側のbsonを使用することは避けたい。
可能であれば、独自定義のbsonを用意して、内部的にgo-mgo/mgoやmongodb/mongo-go-driverに対応可能にしたい。
今後別のMongoDBクライアントを採用する場合に、その変更を独自定義のbsonの範囲に留めておきたいという意図がある。
方法
独自のbsonを定義する。
独自のbsonがgo-mgo/mgoとmongodb/mongo-go-driverの両方で動作することを確認する。
既存のgo-mgo/mgoのbsonを独自のbsonパッケージに置き換える。
go-mgo/mgoを使用したコードをmongodb/mongo-go-driverを使用したコードに置き換える。
課題
現時点で把握している課題。
bson.ObjectIDを定義する
bson.ObjectIDを定義するとして、go-mgo/mgoではGetterとSetterを満たせばよく、mongodb/mongo-go-driverではMarshalerとUnmarshalerを満たせば良さそう。
bson.ObjectIDは下記のように定義する。
type ObjectID primitive.ObjectID
構造体への埋め込みに関しては、この辺が意図通りに動作すれば良さそう。
type target struct {
ID bson.ObjectID `bson:"_id"`
PID *bson.ObjectID `bson:"pid"`
NullPID *bson.ObjectID `bson:"nullpid"`
OmitPID *bson.ObjectID `bson:"omitpid,omitempty"`
}
ref: https://github.com/hirokisan/mgo-to-mongo-go-driver/blob/main/bson/bson_test.go#L16-L22
試したところ、NullPIDが意図通りに動作せず、panicになるため、go-mgo/mgoをforkして変更を加えたところ、意図通りに動作するようになった。
go-mgo/mgoはメンテナンスが終わっているのでforkして変更を加えても良いだろうという判断だった。
ただし、既存のgo-mgo/mgoのbson.ObjectIdの定義が
type ObjectId string
ref: https://github.com/go-mgo/mgo/blob/v2-unstable/bson/bson.go#L166
なので、今回定義するbson.ObjectIDに置き換える際は、primitive.ObjectIDが
type ObjectID [12]byte
であり、stringと[12]byteという差分がある。
その差分が与える影響を考慮しておくと良さそう。
(追記) stringで実装してみた
type ObjectID string
ref: https://github.com/hirokisan/mgo-to-mongo-go-driver/blob/v0.0.2/bson/bson.go#L26
現時点では、ここまで。
bson.Mやbson.Dが意図通りに動作するかは確認したい。
感想
ドメインに近い部分にある構造体にMongoDBの1つのクライアントであるgo-mgo/mgoのbson.ObjectIdを埋め込むと、そのクライアントを別のクライアントに移行する際に結構大変なことになるものだと感じた。
独自定義のbsonを用意して複数のMongoDBクライアントに対応可能にしておくのは1つの手として有効そうではあるが、bsonやMongoDBクライアントを何かしらのパッケージに閉じ込めて利用する側はそのパッケージに依存するようにしておくのも別の手としてはありそう。