Kotlinでデータベースを使おう！②（関連付け・検索）


##**【Kotlin×mBaaS】シリーズ概要**

* Kotlinで[ ニフクラ mobile backend ](http://mbaas.nifcloud.com/)(通称：mBaaS)を使ってKotlinで開発を始めたい人向けのドキュメントです。
* [ ニフクラ mobile backend のAndroid(Java SDK)用ドキュメント](http://mbaas.nifcloud.com/doc/current/index.html#/Android)を**Kotlin**用に書き換えて動かしてみたものをまとめました。
* 初心者でもわかりやすいよう心掛けて作っていますが、わかりにくい部分がありましたらコメントをいただければ訂正しますのでお気軽にご意見をお願いします。
* 今回は**＜データストア編②＞**として関連付け(ポインタ・リレーション)・検索・標準クラスの検索・検索条件・クエリの合成です。
  * 注：「データストア」が[ ニフクラ mobile backend ](http://mbaas.nifcloud.com/)の「データベース」のことです。

##**事前準備のお願い**

* 事前に ニフクラ mobile backend の登録 とアプリの新規作成をし、 [KotlinでmBaaSを始めよう！](https://qiita.com/nifcloud_mb/items/5b6290977f3147c3bc4f)をご覧いただき、必要な初期設定(SDKのインストールなど)をAndroid Studio上で行った上でご利用ください。

##**Kotlinでデータベースを使おう！**

* [ ニフクラ mobile backend ](http://mbaas.nifcloud.com/)のダッシュボードで確認をしながらAndroid Studioで動作確認をしてください。
* ドキュメントの動作確認の方法については[Kotlinでデータベースを使おう！①（保存・取得・更新・削除）](https://qiita.com/nifcloud_mb/items/eef8102fd47bf7e5aa9f)の「ドキュメントの動作確認方法」にまとめてありますので参考にしてみてください。

##**オブジェクトの関連付け**
###**ポインタ**

* NCMBObjectのインスタンスに、別のNCMBObjectを設定すると、設定したNCMBObjectへのポインタが設定されます。
* ポインタ先のオブジェクトがデータストアに登録されていない場合は、ポインタ元のオブジェクトを保存する前に自動で作成されるようになっています。
* 以下の例はobjectクラスのpointerフィールドでchildクラスを参照するサンプルです。

```kotlin:Kotlin
// childクラスを作成（keyフィールドにvalueの値を保存）
var pointer = NCMBObject("child")
pointer.put("key", "value")
pointer.save() /*同期処理*/

// objectクラスを作成
var obj = NCMBObject("object")
// ポインターの設定
obj.put("pointer", pointer)
// 設定されたobjectIdを元にデータストアからデータを取得
obj.saveInBackground { e ->
    if (e != null) {
        // 取得に失敗した場合の処理
    } else{
        // 取得に成功した場合の処理
    }
}
```

##**リレーション**
* ポインタは1つのオブジェクトへの参照しか持つことができないので、複数参照を行いたい場合にはリレーションを利用します。
* リレーションは特定クラスの複数オブジェクトと関連づけることができます。
* リレーションの追加・削除にはNCMBRelationクラスを利用します。
* ポインタでは参照先のオブジェクトが登録されていない場合、自動で作成されましたが、リレーションの場合は自動的に保存されることはありません。
* 以下の例は、PostクラスのcommentsフィールドにNCMBRelationを作成してCommentクラスの２つのオブジェクト（comment1 とcomment2）をリレーション先として設定しているサンプルです。

```kotlin:Kotlin
// リレーション元のオブジェクトを作成
var post = NCMBObject("Post")
post.put("title", "about mobile backend")

// リレーション先1のオブジェクトを作成
var comment1 = NCMBObject( "Comment")
comment1.put("text", "good")
comment1.save()

// リレーション先2のオブジェクトを作成
var comment2 = NCMBObject( "Comment")
comment2.put("text", "bad")
comment2.save()

// commentsフィールドにNCMBRelationを作成
var relation = NCMBRelation.addRelation(arrayListOf(comment1,comment2))
post.put("comments", relation)
post.save()
```

##**オブジェクトの検索**

* 検索には、NCMBQueryクラスを利用します。
* 下記の例は、条件なしで検索を行うサンプルです。クラスのデータが全件検索されます。

```kotlin:Kotlin
val query = NCMBQuery<NCMBObject>("TestClass")

    /** 条件を入れる場合はここに書きます **/

query.findInBackground { objects, e ->
    if (e != null){
        // 検索失敗時の処理
    } else{
        // 検索成功時の処理
    }
}
```

* 「/** 条件を入れる場合はここに書きます **/」とあるところに条件を入れて検索できます。
* 条件については後の項目に書きます。

##**標準クラスの検索**
*  標準で存在するクラスは以表の５つあります。

| クラス名     | 役割                                             |
|--------------|--------------------------------------------------|
| user         | 会員管理クラス                                   |
| role         | データストアのデフォルトクラス(会員グルーピング) |
| installation | データストアのデフォルトクラス(端末情報一覧)     |
| file         | ファイルストアのクラス                           |
| push         | プッシュ通知のクラス                             |


* これらのクラス名を使って、データストアに新規のクラスを作成しようとするとエラーになります。
* 上記のクラス名を指定して、同様にオブジェクト検索を行うことができます。userクラスの検索の場合は以下のようになります。

```kotlin:Kotlin
val query = NCMBQuery<NCMBObject>("user")
```
* userクラスの場合はNCMBUserオブジェクトを使って次のようにクエリを作成することも出来ます。

```kotlin:Kotlin

val query = NCMBUser.getQuery()
```
##**補足**

* 各データにはACL(アクセス権限)設定機能があります。デフォルトでは権限は設定されていません。（誰でも読み書き可能）
* 会員クラス(user)に関してはユーザー本人しか読み書きが行えない設定になっています。上記サンプルを実行する前にダッシュボード上からACL設定を確認してください。詳しくは[＜データストア編③＞](https://qiita.com/nifcloud_mb/items/bf601f57eca8270416ae)で説明します。

##**検索条件の設定**

以下は検索条件のサンプルです。

```kotlin:Kotlin
// keyフィールドの値がvalueと一致するデータを検索する条件
query.whereEqualTo("key","value")
// ["A","B","C"]と一致する配列を検索する条件
query.whereEqualTo("array", arrayListOf("A","B","C"))
// "A"と"B"の両方の値が入っている配列を検索する条件
query.whereContainsAll("array", arrayListOf("A","B","C"))
```

##**ポインタ検索条件の設定**

objectクラスのpointerフィールドに設定されたポインタ(childクラスのデータ)を検索します。※関連付け(ポインタ)で作成したサンプルでで試すことができます。

```kotlin:Kotlin
// childクラスを検索するNCMBQueryを作成
val innerQuery = NCMBQuery<NCMBObject>("child")
// keyフィールドの値でvalueと一致するデーzタを検索する条件を設定
innerQuery.whereEqualTo("key", "value")
// objectクラスを検索するNCMBQueryを作成
val query = NCMBQuery<NCMBObject>("object")
// innerQueryの条件と一致するデータをpointerフィールが参照しているchildクラスのデータから検索する条件を設定
query.whereMatchesQuery("pointer", innerQuery)
// 設定した条件で検索
query.findInBackground { objects, e ->
    if (e != null){
        // 検索失敗時の処理
    } else{
        // 検索成功時の処理
    }

}
```

##**クエリの合成**

検索条件としてand検索やor検索も簡単に指定できます。

###**and検索**

* 条件を複数指定するとand検索をすることができます。

```kotlin:Kotlin
//intフィールドの値が30より上で、50未満の値を検索する条件が設定される
query.whereGreaterThan("int", 30)
query.whereLessThan("int", 50)
```
##**or検索**

* or検索にはorQueryWithSubqueriesメソッドを利用します。

```kotlin:Kotlin
val className = "test"
val query1 = NCMBQuery<NCMBObject>(className)
query1.whereEqualTo("key1", "value1")
val query2 = NCMBQuery<NCMBObject>(className)
query2.whereEqualTo("key2", "value2")
//key1がvalue1であるか、key2がvalue2であるデータを検索する条件

val query = NCMBQuery<NCMBObject>(className)
query.or(mutableListOf(query1, query2) as Collection<NCMBQuery<NCMBBase>>?)
```

##**参考**

* 元サイト
 * [データストア \(Android\) : 基本的な使い方 \| ニフクラ mobile backend](https://mbaas.nifcloud.com/doc/current/datastore/basic_usage_android.html)