Firebase Cloud Firestore + RxJava / RxKotlin のオブジェクト変換

はじめに

Firebase の Cloud Firestore で
DocumentSnapshot または QuerySnapshot から モデルに変換する方法を紹介します。

解決策

Firestoreが用意してくれている toObject 関数を使えば終わりです。

firebase.google.com

FirebaseFirestore.getInstance()
    .collection("users")
    .get()
    .addOnSuccessListener { 
        val cars =  it.toObjects(User::class.java)
    }

使いやすく改良

RxJava / RxKotlin を使用していればもうしこし使いやすくしてみましょう!
そのためには、前回のこの記事も読んでみてください。
qoopmk.hatenablog.jp

ちなみに、toObject に渡している ESTIMATEについてはこちらで説明しています!
qoopmk.hatenablog.jp

/**
 * QuerySnapshotをモデルに変換
 *
 * @return QuerySnapshot
 */
@CheckResult
inline fun <reified T> Single<QuerySnapshot>.toObjects(): Single<List<T>> {
    return map { it.toObjects(T::class.java, DocumentSnapshot.ServerTimestampBehavior.ESTIMATE) }
}

/**
 * DocumentSnapshotをモデルに変換
 *
 * @return DocumentSnapshot
 */
@CheckResult
inline fun <reified T> Single<DocumentSnapshot>.toObject(): Single<T> {
    return map { it.toObject(T::class.java, DocumentSnapshot.ServerTimestampBehavior.ESTIMATE) }
}

結果

このように Firestore のリクエストがすごく簡単になります。

fun findAll(): Single<List<User>> {
    return FirebaseFirestore.getInstance()
        .collection("users")
        .get()
        .toSingle()
        .toObjects()
}

fun findById(id: String): Single<User> {
    return FirebaseFirestore.getInstance()
        .collection("users")
        .document(id)
        .get()
        .toSingle()
        .toObject()
}

注意すべきこと

FirestoreではKotlin data class に変換する際は注意が必要です。
引数のないのコンストラクタがないとエラーになって変換できないので、toObject で指定するdata class にはデフォルト値を入れるか空のコンストラクタを用意しておきましょう!

data class User(
        val id : String = "",
        val name : String = "",
        val age : Int? = null,
)