Edited at

Go言語でMongoDB使う ②埋め込みとの相性


Go言語でMongoDBを使う

前回

でチュートリアル的なものを書きました.

今回は、具体的に使ってて気づいたことを書き留めます.


Goには継承は無いが埋め込みがある

埋め込みについては@tenntennさんがとてもわかりやすい記事を書かれております.

いつもありがとうございます.

で、こんな感じで保存してみます

package main

import (
"fmt"
"github.com/globalsign/mgo"
"github.com/globalsign/mgo/bson"
)

// Personに共通なものはここにまとめたいですよね
type Person struct {
ID bson.ObjectId `bson:"_id"`
Name string `bson:"name"`
Level int `bson:"level"`
}

func (p *Person) Greet() string {
return fmt.Sprintf("My name is %s.", p.Name)
}

// 派生したstructもつくりたいですよね
type Admin struct {
Person
Password string `bson:"password"`
Permissions []string `bson:"permissions"`
}

func main() {
session, _ := mgo.Dial("mongodb://localhost/test")
defer session.Close()
db := session.DB("test")

admin := &Admin{
Person{
bson.NewObjectId(),
"otiai10",
10,
},
"hoge",
[]string{"write", "read"},
}

db.C("people").Insert(admin)
}


埋め込みをそのままInsertすると?

> db.people.find().pretty();

{
"_id" : ObjectId("548eeef9a82a1de844454bd0"),
"person" : {
"_id" : ObjectId("548eeef9b537115caa000001"),
"name" : "otiai10",
"level" : 10
},
"password" : "hoge",
"permissions" : [
"write",
"read"
]
}

埋め込んだPersonpersonという名前のフィールドとしてドキュメントに保存されているのがわかります.

こともあろうかmongo的な_idが二つ作られちゃってて気持ち悪い状況です.


これが嫌なとき

bsonにはinlineというタグキーワードがあります.


inline Inline the field, which must be a struct or a map,

    causing all of its fields or keys to be processed as if

    they were part of the outer struct. For maps, keys must

    not conflict with the bson keys of other struct fields.

フィールドをインライン化します。プリミティブはダメです、structかmapじゃないとダメです。inlineフラグを使うと、そのstructのフィールドは、その外側のstructのフィールドとして処理されます。もしmapを使う場合は、外側のstruct含め、mapのkey名とフィールド名がかぶってはいけません。


とのこと

 type Admin struct {

- Person
+ Person `bson:",inline"`
Password string `bson:"password"`
Permissions []string `bson:"permissions"`
}

そうすっと

> db.people.find().pretty();

{
"_id" : ObjectId("548ef20ab537115cef000001"),
"name" : "otiai10",
"level" : 10,
"password" : "hoge",
"permissions" : [
"write",
"read"
]
}

埋め込んだPersonのフィールドがちゃんとトップレベルのフィールドになってドキュメントに保存されていることがわかります.


これ結構便利なので

encoding/jsonにもinlineタグあったらよくね?」っていうディスカッションがこちらになります.


次回があるなら

「RestAPIでリクエストの扱いとmongoの相性」か、もしくは「database/sqlを使った場合との比較」みたいなものをば.

(Go+MongoDB、わりといいものに見えてきました)