8. オブジェクトストレージ:クエリ

8.1. オブジェクトのクエリ

オブジェクトのクエリは、バケットに対して query() を呼び出すことで行います。

以下の例では、全件検索を行っています。

NbQuery query = new NbQuery();
bucket.query(query,  new NbListCallback<NbObject>() {
    @Override
    public void onSuccess(List<NbObject> objects) {
        // 成功時の処理。
        // objects に検索結果が渡される。
    }

    @Override
    public void onFailure(int statusCode) {
        // 失敗時の処理
    }
});

クエリ条件は、NbQuery クラスを使用して指定します。 NbQuery を生成し、メソッドを呼び出して条件を追加していきます。

注意

クエリ件数上限はデフォルトで100件となっています。 一回のクエリで 100件以上のデータを取得したい場合は、件数上限を明示的に指定する必要があります。

8.2. クエリ条件の指定

検索条件には NbClause を使用します。以下に例を示します。

NbClause clause = new NbClause();

clause.equals("name", "foo"); // 一致条件
clause.lessThan("age", 30); // 比較条件
clause.in("prefecture", "Tokyo", "Kanagawa", "Saitama"); // 配列検索
clause.regex("description", "^[a-c].*", ""); // 正規表現一致

NbQuery query = new NbQuery();
query.setClause(clause);

条件指定メソッドは this を返すので、 上記 clause 生成は以下のように記述することができます。

NbClause clause = new NbClause()
    .equals("name", "foo");
    .lessThan("age", 30);
    .in("prefecture", "Tokyo", "Kanagawa", "Saitama")
    .regex("description", "^[a-c].*", "");

8.2.1. 論理演算

論理演算 (and, or) で複数の NbClause を結合することが可能です。

NbClause clause1 = ...;
NbClause clause2 = ...;

NbClause clause = new NbClause();
clause.or(clause1, clause2);

not 演算子を用いることで、特定のキーに対する条件式を反転することができます。

// 以下は !(score1 > 80) && (score2 > 70) という意味
// score1 フィールドが存在しないオブジェクトにもヒットするが、
// score2 フィールドが存在しないオブジェクトにはヒットしない。
clause.greaterThan("score1", 80).not("score1").greaterThan("score2", 70);


// 以下は (score1 <= 80) && (score2 > 70) という意味
// 上記と似ているが、score1 フィールドが存在しないオブジェクトにはヒットしない点が異なる。
clause.lessThanOrEqual("score1", 80).greaterThan("score2", 70);

8.2.2. オフラインバケットに対するクエリの制限事項

オフラインバケット(レプリカモード、ローカルモード)に対するクエリを 発行することも可能ですが、オンラインモードバケットに比べると いくつかの制限があります。

  • パラメータに null を指定した場合の動作は保証されません
  • 比較演算 (greaterThan など)はスカラ値(数値・文字列)に対してしか動作保証されません
  • 配列に対するスカラ値を指定した配列内検索はサポートされません。代わりに NbClause.in() を使用して下さい。

8.3. ソート順序の指定

ソート順序は、setSortOrders() で指定します。

query.setSortOrders("name", "-age");

ソートキーを引数に指定します。

  • デフォルトのソート順序は昇順です。キーの先頭に "-" を付与すると、降順でソートします。
  • 複数設定した場合は、先に指定したものが優先となります。

8.4. スキップ数・検索上限数の指定

検索におけるスキップ数・上限数は、それぞれ setSkipCount(), setLimit() で指定します。

以下の例では、100件目から最大10件を読むという指定になります。

query.setSkipCount(100).setLimit(10);

なお、上限数の値はデフォルトで 100 となっています。 上限数を無限大(制限なし)にしたい場合は -1 を指定します。

スキップ数・上限数を指定した際に、全ヒット件数を合わせて取得したい場合は setCountQuery() を使用します。

query.setCountQuery(true);

さらに クエリには queryWithCount() を使用します。 コールバックインタフェースの型には NbCountCallback を指定します。 クエリ成功時のコールバック関数の第二引数に全ヒット件数が渡されます。

NbQuery query = new NbQuery();
query.setSkipCount(100).setLimit(100);
query.setCountQuery(true); // 全件数取得
bucket.queryWithCount(query,  new NbCountCallback<List<NbObject>>() {
    @Override
    public void onSuccess(List<NbObject> objects, int num) {
        // 成功時の処理。
        // objects に検索結果が渡される。
        // setCountQuery(true) を指定した場合、num に全ヒット件数が入る。
        // それ以外の場合は num は -1。
    }

    @Override
    public void onFailure(int statusCode) {
        // 失敗時の処理
    }
});

注意

上限数を指定するとヒット件数が上限に達した時点で検索が打ち切られますが、 setCountQuery(true) を指定すると上限数にかかわらず全検索を行うため検索に要する時間が増加します。

8.5. プロジェクション

検索結果に含まれるオブジェクトのフィールドを制限したい場合は、 NbQuery に projection を JSON 形式で指定します。 特定のフィールドのみを取得したい場合は、以下のように指定します。

NbQuery query = new NbQuery();
NbJSONObject projectionJson = new NbJSONObject();
projectionJson.put("name", 1);
query.setProjection(projectionJson);

bucket.query(query,  new NbCallback<List<NbObject>>() {
    @Override
    public void onSuccess(List<NbObject> objects) {
        // 成功時の処理
        // objects に検索結果が渡される
    }

    @Override
    public void onFailure(int statusCode, NbErrorInfo errorInfo) {
        // 失敗時の処理
    }
});

上記を指定した場合、 "id" と指定したフィールド("name")のみを含むオブジェクトが取得されます。

逆に、特定のフィールドのみ抑制したい場合は、以下のように指定します。

projectionJson.put("name", 0);

上記を指定した場合、 "id" と、指定したフィールド("name")以外のフィールドを含むオブジェクトが取得されます。

"id" はデフォルトで付与されますが、省きたい場合は以下のように指定します。

projectionJson.put("name", 1);
projectionJson.put("_id", 0);

上記を指定した場合は、指定したフィールド("name")のみを含むオブジェクトが取得されます。

入れ子構造になっているフィールドを指定する場合は、以下のように指定します。

projectionJson.put("parent.child", 1);

また、 array フィールドに対して、 MongoDB と同様に以下の演算子を使用することも可能です。

  • $elemMatch
  • $slice

注意

"$", "$meta" 演算子は対象外です。