Couchbase Lite機能解説：クエリ① 概要、インデックス、SELECT句


## 概要

Couchbase Liteは、例1に示されている形式のクエリを使用します。

例1.クエリ形式

```sql
SELECT ____ 
FROM 'database' 
WHERE ____, 
JOIN ____ 
GROUP BY ____ 
ORDER BY ____
```

SQL経験者には不要でしょうが、それぞれのキーワードの解説は以下の通りです。

- `SELEC`Tステートメントが結果セットに返されるドキュメントプロパティを指定します
- `FROM`は、ドキュメントを照会するデータベースを指定します
- `WHERE`ステートメントはクエリ基準を指定します。
- クエリ基準に一致するドキュメントの `SELECT`されたプロパティが結果セットに返されます
- `JOIN`ステートメントは、複数のドキュメントを結合するための基準を指定します
- `GROUP BY`ステートメントは、結果セット内の返されたアイテムをグループ化するために使用される基準を指定します
- `ORDER BY`ステートメントは、結果セット内のアイテムの順序付けに使用される基準を指定します

このように、クエリ形式の構造とセマンティクスは、SQLに基づきます。さらに、上記には含まれていませんが、JSONデータの操作に関係する部分では、Couchbase ServerのN1QLクエリ言語に基づいています。

ただし、モバイルアプリケーションという性格上、クエリは文字列で表現するのではなく、オブジェクトとして構築します。 クエリの構築には、ビルダークラス（QueryBuilder）を使用します。

一般に、クエリが文字列として扱われる場合には、文字列を解析して実行するための機能を持つか、プログラミング言語のコンパイラーがソースコードを解析する前に、クエリ文字列をプログラム言語に書き換える（プリコンパイルする）必要があります。モバイルアプリが前者の機能をカバーすることは、フットプリント(アプリのサイズ)を考えると不適切であることがわかります。後者の機能は、提供されていません。

Couchbase Lite 2.0のクエリインターフェイスには、以下の機能が含まれています

- パターンマッチング
- 正規表現マッチング
- 数学関数
- 文字列操作関数
- 集計関数
- グループ化
- 結合（単一のデータベース内）
- 並べ替え
- `NilOrMissing`（未定義値）プロパティ


## インデックス作成
ドキュメントのクエリを開始する前に、クエリインデックスを持つことの重要性について説明します。

クエリは、調査するドキュメントのセットを絞り込むために検索できる既存のデータベースインデックスがある場合に高速になります。インデックスの作成方法を示す例2を参照してください。

例2.新しいインデックスの作成

この例では、示されているデータ形式のプロパティtypeとnameプロパティの新しいインデックスを作成します。

データ形式

```json
[
  { 
    "id": "hotel123",
    "type": "hotel",
    "name": "Hotel Ghia"
  },
  { 
    "id": "hotel456",
    "type": "hotel",
    "name": "Hotel Deluxe",
  }
]
```

インデックスを作成するコード

```java
database.createIndex(
    "TypeNameIndex",
    IndexBuilder.valueIndex(
        ValueIndexItem.property("type"),
        ValueIndexItem.property("name")));
```

ドキュメントが更新されるたびにすべてのインデックスを更新する必要があるため、インデックスが多すぎるとデータ更新時のパフォーマンスが低下する可能性があります。
したがって、アプリケーションのパフォーマンスのバランスを取るために、適切なインデックスを設計・作成することが重要です。

## SELECTステートメント


SELECTステートメントを使用して、クエリされたドキュメントから返すプロパティを指定します。ドキュメント全体を取得するか、必要な特定のプロパティのみを取得するかを選択できます。

### すべてのプロパティを返す
この`SelectResult.all()`メソッドを使用して、選択したドキュメントのすべてのプロパティを返します。

例3を参照してください。

例3.SELECTを使用してすべてのプロパティを取得する
このクエリは、データベース内(の特定の種類のドキュメント)からすべてのプロパティを取得する方法を示しています。

```java
Query query = QueryBuilder
    .select(SelectResult.all())
    .from(DataSource.database(database))
    .where(Expression.property("type").equalTo(Expression.string("hotel")));
```

`query.execute`ステートメントは、結果をディクショナリとして返します。キーはデータベース名です。例4を参照してください。

例4.`SelectResult.all（）`が返すデータ形式の例

```json
[
  {
    "travel-sample": { 
      "callsign": "MILE-AIR",
      "country": "United States",
      "iata": "Q5",
      "icao": "MLA",
      "id": 10,
      "name": "40-Mile Air",
      "type": "airline"
    }
  },
  {
    "travel-sample": { 
      "callsign": "ALASKAN-AIR",
      "country": "United States",
      "iata": "AA",
      "icao": "AAA",
      "id": 10,
      "name": "Alaskan Airways",
      "type": "airline"
    }
  }
]
```


### 選択したプロパティを返す
特定のプロパティのみにアクセスするには、クエリのselectステートメントで、プロパティごとに1つずつ、カンマで区切られたアイテム(`SelectResult.property("<プロパティ名>")`)のリストを指定します。

例5を参照してください。

例5.SELECTを使用して特定のプロパティを取得する
このクエリは、データベース内(の特定の種類のドキュメント)から特定のプロパティを取得する方法を示しています。

```JAVA
    Query query = QueryBuilder.select(
            SelectResult.property("id"),
            SelectResult.property("type"),
            SelectResult.property("name"))
        .from(DataSource.database(database))
        .where(Expression.property("type").equalTo(Expression.string("hotel")));
```

上記の`query`オブジェクトを用いた`query.execute()`コールは、プロパティ名をキーとして、`SelectResult`式ごとに1つずつ、キーと値のペアを返します。例6を参照してください。

例6.結果形式の選択

```java
[
  { 
    "id": "hotel123",
    "type": "hotel",
    "name": "Hotel Ghia"
  },
  { 
    "id": "hotel456",
    "type": "hotel",
    "name": "Hotel Deluxe",
  }
]
```


## 参考情報

https://docs.couchbase.com/couchbase-lite/current/java/querybuilder.html