Go+GAEの環境でCloudDataStoreからデータを取得するときに
- Get()
- GetMulti()
- GetAll()
の挙動の違いでハマったので備忘録として挙動をまとめておきます。
Datasotreのライブラリ
datastore
https://godoc.org/google.golang.org/appengine/datastore
googleappengineには標準でdatastoreのクライアントとして datastore
が用意されています。
僕も使うようになってこの便利さに気づいたのですが、structでRDBでいうところのレコード、datasotreではentityの構造を定義してしまえば、かなり簡単にCRUDの操作ができます。
※ ここでいうentityの構造とはモデルの構造のことです。
goon
https://godoc.org/github.com/mjibson/goon
goonはdatastoreとほぼ同じようなインターフェースを持っていて、自動キャッシュがついているので、キャッシュのことまで考えた場合に使いやすいライブラリです。
データを取得する
goonを使ってDatastoreからentityを取得する場合以下のようにします。
type entity struct { Id int64 `datastore:"-" goon:"id"` Field_1 string Field_2 string } func GetInstances(r *http.Request){ g := goon.NewGoon(r) entity := &entity{ID:1} g.Get(entity) // ID(key) = 1のentityを取得する }
goon.NewGoon(r)
としている箇所はhttp.Requestから新規でappengineのContextを作成しています。NewGoon
メソッドの内部はgoonのソースコード読むと
// NewGoon creates a new Goon object from the given request. func NewGoon(r *http.Request) *Goon { return FromContext(appengine.NewContext(r)) }
ちなみに以下のような書き方も可能
g := goon.NewGoon(r) entity := &entity{ID:1} g.Goon().Get(entity) // ID(key) = 1のentityを取得する
とあるので、ここでappengineから新しくContext作っているのが一目瞭然ですね。
遭遇したエラー
Datastoreからデータを取得するときに以下のエラーに遭遇しました。
順を追ってどうしてエラーが発生したのか見ていきます。
goon: cannot find a key for struct
goon: Expected dst to be a pointer to a slice or nil, got instead
invalid entity type
1. goon: cannot find a key for struct
こちらはGet()とGetMultiが ID(key)
をKeyにしないとDatastoreからデータを取得できない性質を持っているということを知らなかったために発生しました。
RDBのようにprimaryキーだけでなく別のfieldをフックにしてデータを取得したい場合があると思います。
しかし、DataStoreのGet()とGetMulti()はID(DatastoreでいうところのprimaryKey)をKeyに取ることしかできません。
そのため、ID以外のfieldをKeyにしたい場合には上記2つのメソッドではなく、GetAll()メソッドを使ってクエリを直に指定する必要があります。
query.Filter("someFiled =", hogehoge)
とqueryでFilterを指定すれば可能。
2. goon: Expected dst to be a pointer to a slice or nil, got instead
これはGetAll()を使うときに発生しました。
dstは GetAll(query *datastore.Query, dst interface{})
とあるようにGetAll()メソッドの第二引数です。
DataStoreからデータを取得する場合には dst
に対して指定した参照型の変数にデータが格納されて入ってきます。
これがそのまま、DataStoreから取得したデータの結果になります。
そのため、dstには slice化されたpointer型の変数
もしくは何も指定指定しない nil
しかいれることができません。
上記のサンプルでも entity
が参照型になっています。
3. invalid entity type
これも2と要点は同じなんですが、Datastoreから取得したEntityの入れ物となる参照型の変数の構造は取得したいDatastoreのkindのfield構成と一致している必要があるそうです。
言われてみれば当たり前のような気もしますが、参照型、かつ構造が同じでないといけません。
Datastoreのルールで詰まったり、構造で詰まったり、そもそもなぜdstは参照型で渡すのか、色々知るいい機会になりました。