FirestoreにINQueryが対応されたのでSDK,Ballcapで試してみる

# この記事について

FirestoreでついにIN句がサポートされましたね:v:

Firestoreでは投げれないQueryをAlgoliaにお任せするようなケースはありそうですが、
今回の更新によってOR検索についてはAlgoliaに頼らずともFirestoreで完結してできそうですね！(制限の内容にもよりますが:sweat_smile:)

そこで今回はSDK,FirestoreのラッパーライブラリであるBallcapそれぞれで試してみた内容とIN句の制限について書いてみました:hugging:
# 前提
FirestoreにMoviesCollectionを用意し、
複数のDocumentがMoviesCollectionに入ってる状態を作ってます。

全体的なPathイメージはこちら
`/movies/{movieId}`

<img width="824" alt="スクリーンショット 2019-11-08 16.44.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75593/df0438ce-3b29-2979-95c7-36b04163f5ee.png">

各Documentのデータ内容
<img width="1021" alt="スクリーンショット 2019-11-08 16.43.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75593/f3905918-fb2f-9a4c-bbb8-3172f083f7d8.png">

Ballcap使用の場合についても今回の記事で触れるためModelについて

```swift
import Ballcap

struct Movies: Codable, Equatable, Modelable {
    var name: String = ""
    var category: [String] = []
    var tag: String = ""
}
```
# IN Query
tagFieldにnewもしくはrecommendが存在しているDocumentを取得

**SDK**

```swift
db.collection("movies")
    .whereField("tag", in: ["new", "recommend"])
    .addSnapshotListener { (querySnapshot, error) in
        if let error = error {
            print(error)
        }
        if let documents = querySnapshot?.documents {
            for doc in documents {
                print("data:\(doc.data())")
            }
        }
}
```

**Ballcap**

```swift
Document<Movies>
    .where("tag", in: ["new", "recommend"])
    .dataSource().onCompleted { (_, movies) in
        for movie  in movies {
            print("movie:\(movie.data?.name)")
        }
}.get()
```
# ArrayContainAny Query
categoryFieldにhorrorもしくはthrillerが存在しているDocumentを取得
**SDK**

```swift
db.collection("movies")
    .whereField("category", arrayContainsAny: ["horror", "thriller"])
    .addSnapshotListener { (querySnapshot, error) in
        if let error = error {
            print(error)
        }
        if let documents = querySnapshot?.documents {
            for doc in documents {
                print("doc:\(doc.data())")
            }
        }
}
```

**Ballcap**

```swift
Document<Movies>
    .where("category", arrayContainsAny: ["horror", "thriller"])
    .dataSource().onCompleted { (_, movies) in
        for movie in movies {
            print("movie:\(movie.data?.name)")
        }
}.get()
```
# 制限について
IN Queryに対する制限は以下二つになります。
`現在、クエリでは最大10個の異なる値に制限されています。`

```swift
// 10件まで！
whereField("number", in: ["1","2","3","4","5","6","7","8","9","10"])
```

`単一のクエリでは、これらのタイプの操作のうち1つのみを使用できます`

```swift

// 新しくFiledを設けてうまく使えば制限超えれるのでは？もダメ
whereField("number", in: ["1","2","3","4","5","6","7","8","9","10"])
whereField("number2", in: ["11","12","13","14","15","16","17","18","19","20"])
```

ちなみに10件超える場合はクラッシュします:angel_tone5:

```
reason: 'Invalid Query. 'arrayContainsAny' filters support a maximum of 10 elements in the value array.'
```

```
reason: 'Invalid Query. 'in' filters support a maximum of 10 elements in the value array.'
```

# 参考
[Cloud FirestoreでINクエリがサポートされるようになりました！](https://firebase.googleblog.com/2019/11/cloud-firestore-now-supports-in-queries.html)

[Querying and filtering data](https://cloud.google.com/firestore/docs/query-data/queries#in_and_array-contains-any)

[Firestore](https://github.com/firebase/firebase-ios-sdk/tree/master/Firestore)
↑ここの更新ちらほらみてるとリリース発表前に気付けたりします
# 使用したライブラリ
[Ballcap-iOS](https://github.com/1amageek/Ballcap-iOS)

# 余談

お世話になってるライブラリに今回のIN句対応がmergeされました:v:
まだまだ中身追いきれてないですがQueryあたりは直近でみてたのでタイミングがよかったです!
<img width="1021" alt="スクリーンショット 2019-11-08 17.41.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75593/e298ed36-5465-8a88-7c3d-d796a862701f.png">