GAE/Go datastore のメモ
GAE標準のNoSQLストレージである Datastore の個人的備忘録メモです。
※この記事は基本的に公式ドキュメントの書き写しです。
エンティティ
エンティティとは
- キーに関連付けられたDatastoreの保存の際の基本単位
- エンティティはユニーク識別子である キー を持つ
- エンティティはオプションとして親エンティティを持てる
- よってエンティティは全体として、ファイルシステムのような階層化構造となる
エンティティのキーとは
- 以下のいずれかの要素からなる。
- 文字列のアプリケーションID
- エンティティタイプ(文字列のカインド)
- 数値(int64)キー
- 文字列(string)キー
- 文字列のキーはエンティティ名, キー名とも呼ばれる
- 親キー(オプション)
- string, int64 のゼロ値のキー
- インコプリートキーと呼ばれる
- 保存されたどのエンティティも参照していない状態を表す
- インコプリートキーのエンティティをDatastoreに保存すると自動でユニークなキーが生成されて保存される
祖先パス
- エンティティ作成時、オプションで別のエンティティを「親」として設定できる
- このとき親エンティティは実際に存在していなくてもOK
- エンティティの親子関係は作成後の変更はできない
- 一度親を設定したら変更できないし、あとから親を設定することもできない
- ルートエンティティから親子関係を辿って対象のエンティティまでの連なりを祖先パスという
エンティティグループとは
- 親のないエンティティ を rootエンティティと呼ぶ
- 同じ祖先からたどるエンティティは同じエンティティグループに属する
- つまり、ルートエンティティ以下の全てのエンティティのこと
- 同じ祖先のエンティティのキーは、グループの親キーとなり、そのエンティティグループを表す。
- 同じ祖先からたどるエンティティは同じエンティティグループに属する
- エンティティグループに対するクエリを
ancestor queries
と呼ぶ- 親キー対して発行する
- エンティティグループは 一貫性とトランザクションのユニット
- 常に最新の結果を返せる。
- 複数のエンティティグループにまたぐクエリは、古い状態の値を返すことがある
- Eventual Consistency(結果整合性)というやつ
- 1つのエンティティグループにまとめる(同じ祖先を持つ)と常に最新のデータを取得できる
- Strong Consistency(強い整合性)というやつ
- 制約として、同エンティティグループには、1秒1件しか書き込めない
- memcacheサービスなどで軽減は可能かもしれない
- システムから割り当てられる ID値はエンティティグループに対して一意になる
エンティティの内容
- フィールド名は大文字/小文字を区別する
- 通常は構造体のポインタ
-
PropertyLoadSaver
インターフェースを実装した任意の型でもOK
-
PropertyLoadSaver Interface
- エンティティの内容は
PropertyLoadSaver
インターフェースを実装した任意の型で表せる。- 構造体のポインタである必要はない
-
Load
はコンテンツの読み込み時,Save
は保存時に呼び出される
実装例
// 以下の CustomPropsExample はエンティティのプロパティとして使用可能
// 通常の埋め込み構造体より機能が追加されている(Sumの計算)
type CustomPropsExample struct {
I, J int
// Sumはdatastoreには保存されないが, 常に I+J の値となる
Sum int `datastore:"-"`
}
func (x *CustomPropsExample) Load(ps []datastore.Property) error {
// I, J を通常通り Load する
if err := datastore.LoadStruct(x, ps); err != nil {
return err
}
// Sumフィールドを埋める
x.Sum = x.I + x.J
return nil
}
func (x *CustomPropsExample) Save() ([]datastore.Property, error) {
// Sumフィールドのバリデーション
if x.Sum != x.I + x.J {
return errors.New("CustomPropsExample has inconsistent sum")
}
// I, J を通常通り Save する. 以下のコードは "return datastore.SaveStruct(x)" と等価だが
// 今回はサンプル提示のため, 手動で行っている
return []datastore.Property{
{
Name: "I",
Value: int64(x.I),
},
{
Name: "J",
Value: int64(x.J),
},
}
}