Parse.com を使ってバックエンドを構築した時、Android からは、ParseSDK を用いてそれらにアクセスするのが最も簡単かつ手軽にできます。
そして、Parse に保存されたデータにアクセスする際頻繁に使うであろうクラスが、ParseQuery
です。
ParseQuery の概要
ParseQuery は、指定した条件を満たすレコードの一覧を得るために使います。
例えば、あるカラムの数字が x 以上だとか、あるカラムの文字列が y と一致するとか、レコードのオフセットやリミットも指定できます。
リレーショナルなレコード
Parse のデータベースは、リレーショナルなデータを持たせることが出来、いくつかの種類があります。
Pointer
カラムのデータが、別のクラスが持つ特定のレコードを指し示す場合に用いられます。リレーショナルデータベースで言うところの外部キーのように働きます。
Relation
名前の通り、関係を持っているデータの集合を取り扱うための型です。リレーショナルデータベースであれば、関係テーブルを用いて表現する内容を、カラムの型として取り扱えるようにしてくれています。
ParseQuery の使い方
Pointer
とRelation
以外は、特に指定のない限りデフォルトでどの型のカラムであっても結果として取得することが出来ますが、Pointer
とRelation
は特別扱いされ、リクエストの際に指定しない限りレスポンスには存在しない事になったり、そもそも取得の方法が別に用意されていたります。
Pointer を含める
ParseQuery#include(String)
で、引数に指定したカラムのPointer
の内容を一緒に返してくれます。
Pointer
で指定したデータの中に、別のクラスのPointer
を型とするカラムがある場合、別途それも含まれるよう指示しないと結果が得られません。
ParseQuery<Hoge> query = new ParseQuery<Hoge>(); // Hoge クラスのテーブルにクエリを投げる
query.include("huga"); // Huga クラスのデータを持つ huga カラムに対し、インクルード指定することで、huga カラムに指定された Huga クラスのレコードが返ってくるようになる
query.include("huga.piyo"); // Huga クラスの piyo カラムは Piyo クラスへの Pointer である為、ドットでつないでインクルードする
query.include("huga.piyo.foo");
query.include("huga.piyo.foo.bar");
query.include("huga.piyo.foo.bar.baz"); // ドットは 3 個までの制約があるため、インクルード出来ない
言うまでもなく、インクルードが増えれば増えるほどレスポンスが返ってくるまでの時間は長くなります。
Relation を含める
Pointer
のようには含められません。
ではどうするかというと、ParseQuery
の結果からParseRelation
を取得し、このParseRelation
が持つクエリを使って再度リクエストを投げることになります。
ParseQuery<Hoge> query = new ParseQuery<Hoge>();
List<ParseObject> result = query.find();
for (ParseObject object: result) {
ParseRelation relation = object.getRelation("data");
ParseQuery relationQuery = relation.getQuery();
List<ParseObject> relationResult = relationQuery.find();
...
}
言うまでもなく、取得したいRelation
の数だけクエリを発行してfor
文を回すので、最初にリクエストを生成してから、最終的な結果を得るまでには相当の時間を費やすことになります。
Relation のパフォーマンスチューニングをしたい
例えば、関係を多数持つカラムを考えた時、その上限が明らかになっている場合、Pointer
の配列型としてカラムを定義する手段がありえます。
Parse のデータベースのカラムには、配列型が存在し、内部的には数字や文字列以外も配列として保持することが出来、Pointer
も配列にすることが可能です(とは言え、Relation
の配列を作れるかどうかは未検証ですが…)。
こうすることで、ParseQuery#include(String)
を用いて、一回のリクエストですべての関係を引いてくることが出来るようになります。
もうfor
文をネストしてその中で何度もリクエストを飛ばすようなこともなくなります。
まとめ的な
ParseSDK はとかく内部で色々やっているらしく、ミューテックスを使って何らかロックを取得しているようですし、**InBackground()
でも平気で MainThread をブロックしに来てくれますし、わりと効率の悪い感じがあるので、できれば REST ですべてをさばけるようになるとシアワセかもしれません。