The Round

合同会社ナイツオの開発ブログ

[PR] 5分から相談できるGCP™ 開発コンサル!→こちら

GAE/Go プロジェクションクエリ

注:古い記事の為、内容が最新ではない可能性がありますm(_ _)m

こんにちわ!マツウラです。
前々回、前回と引き続きGo言語によるApp Engine Datastoreクエリについてです。
今回はエンティティ全体を取得する通常のクエリに対して、任意のプロパティ値のみを取得することが可能なプロジェクションクエリについてです。
それではGo言語での基本的な使い方を見てゆきます。

参考:Go — Google Developers Projection Queries

Projection Queries

多くの場合、アプリケーションが必要とするのはいくつかのプロパティだけです。
プロジェクションクエリは必要なプロパティについてのみ照会することが出来ます。

プロジェクションクエリはSQLクエリに似ています。

SELECT name, email, phone FROM CUSTOMER

プロジェクションクエリでは標準的なエンティティクエリで使用可能であったフィルタリングやソート機能はすべて使用することが可能です。
クエリは設定したプロパティのみに要約した結果を返します。その他のプロパティ値は持ちません。

Goでプロジェクションクエリを使う

プロジェクションクエリを作成するには、Projectメソッドを使います。

q := datastore.NewQuery("People").Project("FirstName", "LastName")

クエリの結果の処理は標準的なエンティティを取得するクエリと同じです。

次の例はEventLogエンティティのTitle, DateWrittenプロパティについてのクエリです。
DateWrittenで昇順ソートし、各プロパティ値をログに書き込みます。

c := datastore.NewContext(r)
q := datastore.NewQuery("EventLog").Project("Title", "ReadPath", "DateWritten").Order("DateWritten")
iter := q.Run(c)
for {
    var e EventLog
    _, err := iter.Next(&e)
    if err == datastore.Done {
        break
    }
    if err != nil {
        c.Errorf("Running query: %v", err)
        break
    }
    c.Infof("Log record: %v, %v, %v", e.Title, e.ReadPath, e.DateWritten)
}

制限

  • インデックス付きプロパティのみ
    500文字以上になる文字列、要素数が500以上のbyte配列、明示的にインデックス付けされていないプロパティは非サポートです。
  • 同じプロパティを複数回指定することはできない
  • (=, IN)のフィルタで参照されるプロパティは指定できない
SELECT A FROM kind WHERE B = 1
SELECT A FROM kind WHERE A > 1

これらはプロジェクションプロパティで等式フィルタが使われおらず、また等式フィルタがそもそも使われていないので有効ですが、

SELECT A FROM kind WHERE A = 1

このようにプロジェクションプロパティで等式フィルタを使用する場合は無効です。

  • プロジェクションクエリによって返る結果はデータストアに保存しない方が良い
    ここで返される結果は不完全なエンティティデータになるので、データストアに書き込むと従来のエンティティを損なうことになります。

複数の値を持つプロパティ

複数の値を持つプロパティに対してプロジェクションクエリを実行しても、その値をそのまま全て取得することは出来ません。
代わりに、クエリに一致するプロジェクション値の一意の組み合わせ毎に、別々のエンティティとして返されます。

例えば、複数の値をもつプロパティAとBを持つ種類Fooのエンティティがあるとします。

entity := Foo{A: []int{1, 1, 2, 3}, B: []string{"x", "y", "x"}}

次のプロジェクションクエリは以下の組み合わせで4つのエンティティが返されます。

q := datastore.NewQuery("Foo").Project("A", "B").Filter("A <", 3)
  • A = 1, B = 'x'
  • A = 1, B = 'y'
  • A = 2, B = 'x'
  • A = 2, B = 'y'

App Engineでお決まりのことですが、プロパティに複数の値をもっているものに対してクエリを実行する場合、インデックス爆発を起こす恐れがあるので注意して下さい。

インデックス

プロジェクションクエリはプロジェクションで指定する全てのプロパティについてデータストアインデックスが必要です。
App Engineの開発サーバーでは、インデックス設定ファイルであるindex.yamlに必要なインデックスを自動的に生成し、アプリケーションと一緒にアップロードされます。

テストなどで全てのクエリを試行している場合はあまり気にする必要はないかもしれません。


今回はプロジェクションクエリについて基本的な部分を見てゆきました。
次回はトランザクションについて見てゆきます。