【Firebase】Cloud Firestoreのデータ追加、取得サンプル(Kotlin)

##〇概要
FirebaseのCloud Firestoreの[公式サイト](https://firebase.google.com/docs/firestore/manage-data/add-data)にKotlinのサンプルがない！と思い、まとめました。
ところが完成間際に[言語を英語](https://firebase.google.com/docs/firestore/manage-data/add-data?hl=en)にしたら書いてあって血を吐きそうになりました・・・

それでも、分かりづらいところもあり、まとまっていると便利なので書いておきます。
ライブラリの追加や初期化などの設定は省きます。（参考のサイトに書いてあります）

##〇データ形式
Collection → Document → Fieldの順
DocumentにFieldと一緒にCollectionを入れて階層を深くすることも可能です。
Collection → Document → Collection → Document → ・・・ → Field

##〇追加
###・Collection,DocumentにFieldを追加
データはMapに入れるよりもdata classに設定するとスマートな気がします。
未登録のCollection,Documentだと新規作成されて、
登録済みのCollection,Documentだと上書き保存されます。
下記例から.document()を削除すれば、ランダムでユニークなIDが自動で付与されます。


```Kotlin:dataクラスとインスタンスの取得
data class UserItem(
    val firstName: String = "",
    val lastName: String = "",
    val age: Int = 0,
    val adult: Boolean = false,
    val state: String = "",
    val regTime: Date = Date())

val user = UserItem("Ichiro","Suzuki",55,true,"TOKYO")
```
```Kotlin:追加関数と呼び出し
fun addData(db:FirebaseFirestore,user:UserItem,collection:String,document:String){
    db.collection(collection)
       .document(document)
       .set(user)
       .addOnSuccessListener { documentReference ->
           Log.d(TAG, "addData")
       }
       .addOnFailureListener { e -> Log.d(TAG, "Error adding document" + e)}
}

addData(db,user1,"users","u001")
```

###・Collection,DocumentにCollectionを追加
```Kotlin:Documentに登録するdataクラスとインスタンスの取得
data class HobbyItem(
    val firstHobby: String = "Ski",
    val year: Int = 3)

val hobby = CloudFirestoreHelper.HobbyItem("Ski",3)
```

```Kotlin:追加関数と呼び出し
fun addDataSecondCollection(db:FirebaseFirestore,hobby:HobbyItem,collectionFirst:String,documentFirst:String,collectionSecond:String,documentSecond:String){
    db.collection(collectionFirst)
        .document(documentFirst)
        .collection(collectionSecond)
        .document(documentSecond)
        .set(hobby)
        .addOnSuccessListener { documentReference ->
            Log.d(TAG, "addDataSecondCollection")
        }
        .addOnFailureListener { e -> Log.d(TAG, "Error adding document" + e)}
}
addDataSecondCollection(db,hobby1,"users","u001","hobby","h001")

```

##〇取得
###・Collection,Documentを指定してFieldを取得
```Kotlin:取得関数と呼び出し
fun getData(db:FirebaseFirestore,collection:String,document:String){
    db.collection(collection)
        .document(document)
        .get()
        .addOnCompleteListener { task ->
        if (task.isSuccessful) {
            val document = task.result
            if (document != null && document.data != null) {
                Log.d(TAG, "getData")
                Log.d(TAG, "DocumentSnapshot data: " + document.data?.get("firstName"))
                Log.d(TAG, "DocumentSnapshot data: " + document.data?.get("lastName"))
                Log.d(TAG, "DocumentSnapshot data: " + document.data?.get("age"))
                Log.d(TAG, "DocumentSnapshot data: " + document.data?.get("regTime"))
            } else {
                Log.d(TAG, "No such document")
            }
        } else {
            Log.d(TAG, "get failed with " + task.exception)
        }
    }
        .addOnFailureListener { e -> Log.d(TAG, "Error adding document" + e)}
}

getData(db,"users","u001")
```

###・Collection,Document,Collection,Documentを指定してFieldを取得
```Kotlin:取得関数と呼び出し
fun getDataSecondCollection(db:FirebaseFirestore,collectionFirst:String,documentFirst:String,collectionSecond:String,documentSecond:String){
    db.collection(collectionFirst)
        .document(documentFirst)
        .collection(collectionSecond)
        .document(documentSecond)
        .get()
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                val document = task.result
                if (document != null && document.data != null) {
                    Log.d(TAG, "getDataSecondCollection")
                    Log.d(TAG, "DocumentSnapshot data: " + document.data?.get("firstHobby"))
                    Log.d(TAG, "DocumentSnapshot data: " + document.data?.get("year"))
                } else {
                    Log.d(TAG, "No such document")
                }
            } else {
                Log.d(TAG, "get failed with " + task.exception)
            }
        }
        .addOnFailureListener { e -> Log.d(TAG, "Error adding document" + e)}
}
CloudFirestoreHelper.getDataSecondCollection(db,"users","u001","hobby","h001")
```

###・Collectionを指定して全Fieldを取得
```Kotlin:取得関数と呼び出し
fun getDataAll(db:FirebaseFirestore,collection:String){
    db.collection(collection)
        .get()
        .addOnCompleteListener{ task ->
            if (task.isSuccessful) {
                val document = task.result
                if (document != null && document.toObjects(UserItem::class.java) != null) {
                    val userList = document.toObjects(UserItem::class.java)
                    Log.d(TAG, "getDataAll")
                    Log.d(TAG, "userList.size " + userList.size)
                    for(i in 0 until  userList.size){
                        Log.d(TAG, "userList.get(" + i + ").firstName " + userList.get(i).firstName)
                        Log.d(TAG, "userList.get(" + i + ").lastName " + userList.get(i).lastName)
                        Log.d(TAG, "userList.get(" + i + ").age " + userList.get(i).age)
                        Log.d(TAG, "userList.get(" + i + ").regTime " + userList.get(i).regTime)
                    }
                }
            } else {
                Log.d(TAG, "No such document")
            }
        }
}

getDataAll(db,"users")
```

###・Collectionを指定して色んな条件でFieldを取得
Where,Limit,OrderBy,Betweenを設定
####注意
・等価演算子（==）と範囲比較（<、<=、>、>=）を組み合わせる場合はインデックスの作成が必要
・OrderByは複数指定も可能
・OrderByにカンマ区切りでQuery.Direction.DESCENDINGを付ければ逆順
・Betweenは境界値を含みたい場合startAfter()とendBefore()を使用
　　- 下記例では40 <= age <= 60

```Kotlin:取得関数と呼び出し
fun getDataConditions(db:FirebaseFirestore,collection:String){
    db.collection(collection)
        .whereEqualTo(UserItem::state.name,"TOKYO")
        .orderBy(UserItem::age.name)
        .startAt(40)
        .endAt(60)
        .limit(2)
        .get()
        .addOnCompleteListener{ task ->
            if (task.isSuccessful) {
                val document = task.result
                if (document != null && document.toObjects(UserItem::class.java) != null) {
                    val userList = document.toObjects(UserItem::class.java)
                    Log.d(TAG, "getDataOrderByLimit")
                    Log.d(TAG, "userList.size " + userList.size)
                    for(i in 0 until  userList.size){
                        Log.d(TAG, "userList.get(" + i + ").firstName " + userList.get(i).firstName)
                        Log.d(TAG, "userList.get(" + i + ").lastName " + userList.get(i).lastName)
                        Log.d(TAG, "userList.get(" + i + ").age " + userList.get(i).age)
                        Log.d(TAG, "userList.get(" + i + ").regTime " + userList.get(i).regTime)
                    }
                }
            } else {
                Log.d(TAG, "No such document")
            }
        }
}

getDataConditions(db,"users")
```

####Where一覧

・=
WhereEqualTo()
・!=
WhereNotEqualTo()
・<
WhereLessThan()
・<=
WhereLessThanOrEqualTo()
・>
WhereGreaterThan()
・>=
WhereGreaterThanOrEqualTo()

##〇参考
・公式
https://firebase.google.com/docs/firestore/
https://firebase.google.com/docs/firestore/?hl=en
・Firebase Cloud Firestoreの使い方
　- 公式にない情報が網羅されています。
https://qiita.com/subaru44k/items/a88e638333b8d5cc29f2
・AndroidでFirebaseのCloudFirestoreを使ってみた(Kotlin)
　- インストールからKotlinでの使い方まで書いてあります。
https://qiita.com/morayl/items/c14741ebf17b7c9e4e8b