#この記事の目的#
Go言語によるデータストアの頻出処理をメモ
随時更新
#公式ドキュメント#
datastore - GoDoc
goon - GoDoc
#前提知識#
RDBと比較して知識整理
Concept | Datastore | RDB |
---|---|---|
Category of object | Kind | Table |
One object | Entity | Row |
Individual data for an object | Property | Field |
Unique ID for an object | Key | Primary Key |
Memcacheについても、軽い記事を書きました。
#ダミーデータ
以下のようなデータを対象としてみる。 (参考: 拙著「エンティティの関連付けパターン」)
なお、datastoreのオプションについては→補足知識
import "google.golang.org/appengine/datastore"
type Parent struct {
ID string `datastore:"-" goon:"id"`
Name string `datastore:"Name,noindex"`
Age string `datastore:"Age,noindex"`
}
type Child struct {
Parent *datastore.Key `datastore:"-" goon:"parent"`
Name string `datastore:"Name,noindex"`
}
import "dataobj"
var Parent1 = &dataobj.Parent{
ID : "123",
Name : "玉子",
Age : "40",
}
#頻出関数#
##Goonインスタンスの生成##
定義: NewGoon(r *http.Request) *Goon
g := goon.NewGoon(r)
##Keyの取得 方法1##
定義: NewKey(c context.Context, kind, stringID string, intID int64, parent *Key) *Key
parent_key := datastore.NewKey(c, "Parent", "123", 0, nil)
☆親を持つエンティティのkeyを取得したい場合は、「stringIDあるいはintID」+「parentKey」の両方を指定しなければならない。エンティティグループを組むとこの点が面倒。
##Keyの取得 方法2##
定義: (g *Goon) Key(src interface{}) *datastore.Key
parent := &dataobj.Parent{ID: "123"}
parentKey := g.Key(parent)
##データの保存##
定義: (g *Goon) Put(src interface{}) (*datastore.Key, error)
// Parent1を保存
g.Put(Parent1)
// 上述のparent_keyを親Keyに持つChildを2人保存
g.Put( &dataobj.Child{ Parent: parentKey, Name: "のびた"} )
g.Put( &dataobj.Child{ Parent: parentKey, Name: "どらえもん"} )
##Kindを指定するクエリを生成##
定義: NewQuery(kind string) *Query
q := datastore.NewQuery("Parent")
##親Keyを条件に付したクエリの生成##
定義: (q *Query) Ancestor(ancestor *Key) *Query
トランザクション内でも実行可能
q := datastore.NewQuery("Child").Ancestor(parentKey)
##クエリに合致するデータを全取得##
定義: (g *Goon) GetAll(q *datastore.Query, dst interface{}) ([]*datastore.Key, error)
// 取得データを受け止める配列を用意
var childs []*dataobj.Child
// クエリに基づき全て取得
g.GetAll(q, &childs)
// Keyのみを取得したい場合は、こんな感じ
q := datastore.NewQuery("Parent").KeysOnly()
keys, err := g.GetAll(q, nil)
##エンティティの取得##
定義: (g *Goon) Get(dst interface{}) error
parent := &dataobj.Parent{ID:"123"}
err := g.Get(parent)
if err!= nil {
// エラー処理
}
// Propertyを参照してみる
name := parent.Name
##エンティティの取得(複数)##
定義: (g *Goon) GetMulti(dst interface{}) error
KeysOnlyクエリと相性が良い
// 取得データを受け止める配列を用意。 idsは、1~10のstring配列とする
parents := make([]*dataobj.Parent, len(ids))
for i, id := range ids {
parents[i] = &dataobj.Parent{ID: id}
}
// IDが1~10のParentエンティティを一括取得
g.GetMulti(parents)
##KeyからIDを取得する##
定義: (k *Key) StringID() string
entity name あるいは key nameとも呼ばれる。
// Child.Parentに親Keyが入っているとする
parentID := Child.Parent.StringID()
##クエリの取得件数をカウント##
定義: (g *Goon) Count(q *datastore.Query) (int, error)
なお、Countは内部でKeysOnly
を付加しているため、クエリ生成時に付加する必要はない
count, err := g.Count(q)
##フィルター付きクエリの生成##
定義: (q *Query) Filter(filterStr string, value interface{}) *Query
// プロパティに対して (<, >, <=, >=, = の5種)
q := datastore.NewQuery("Parent").Filter("Age =", 40)
// keyに対して
q := datastore.NewQuery("Parent").Filter("__key__ =", key)
ちなみに、sliceに対しても検索は可能 (参考: 拙著「エンティティのsliceプロパティを条件に検索する」)
##ソート順を指定したクエリの生成##
定義: (q *Query) Order(fieldName string) *Query
// Ageの降順でソート
q := datastore.NewQuery("Parent").Order("-Age")
#補足知識
##datastoreのタグ名##
"" :単にフィールド名を使用
"-":データストアがそのフィールドを無視する
##datastoreのオプション##
"omitempty"
フィールドの値が空の場合、自動保存される。
(false、0、任意のnilインタフェース値、長さ0の配列、スライス、マップ、文字列)
"noindex"
インデックスを登録しない。
長い文字列とバイトスライスを格納するために使用されるフィールドには必須のオプション。
#必読リスト!
- 公式 Cloud Datastoreのベストプラクティス
- 公式 トランザクションについて
- 公式 強整合性と結果整合性のバランス
- 公式 Datastoreでのデータ整理の考え方
- Datastore/Goのデータ設計のコツ
- Datastoreのデザインパターン
- GAE Datastoreについて
- GAEでハマったこと
- Cloud Datastore 活用術
- GAE/Goのdatastoreの挙動について
- DatastoreのプロジェクションクエリをGoon経由で発行してはいけない
他にもあればコメントお願いします