web-dev-qa-db-ja.com

kotlinデータクラスを使用してFirestoreドキュメントのドキュメントIDを取得する方法

Kotlinデータクラスがあります

data class Client(

    val name: String = "",
    val email: String = "",
    val phone: String ="") {
constructor():this("","","")}

Firestoreでデータをクラスに適切に設定していますが、ドキュメントIDをドキュメント自体に設定せずにデータIDを取得する方法を見つけようとして途方に暮れています。これは可能ですか?

11
ZerroShadows

はい、DocumentSnapshotを使用して、保存せずにidを取得することができます。ここで完全な例を構築してみます。

IDを保持する一般的なModelクラスを作成しました:

_@IgnoreExtraProperties
public class Model {
    @Exclude
    public String id;

    public <T extends Model> T withId(@NonNull final String id) {
        this.id = id;
        return (T) this;
    }
}
_

次に、任意のモデルで拡張し、何も実装する必要はありません。

_public class Client extends Model
_

ここにクライアントのリストがある場合、リストを照会して_age == 20_を持つクライアントのみを取得しようとします:

_clients.whereEqualTo("age", 20)
        .get()
        .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
            @Override
            public void onComplete(@NonNull Task<QuerySnapshot> task) {
                if (task.isSuccessful()) {
                    for (DocumentSnapshot documentSnapshot : task.getResult().getDocuments()) {
                        // here you can get the id. 
                        Client client = document.toObject(client.class).withId(document.getId());
                       // you can apply your actions...
                    }
                } else {

                }
            }
        });
_

また、EventListenerを使用している場合は、次のようなIDも取得できます。

_clients.addSnapshotListener(new EventListener<QuerySnapshot>() {
    @Override
    public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
        for (DocumentChange change : documentSnapshots.getDocumentChanges()) {
            // here you can get the id. 
                        Client client = document.toObject(client.class).withId(document.getId());
                       // you can apply your actions...
        }
    }
});
_

documentSnapshot.getId()) は、ドキュメントにIDを保存せずに、コレクション内のドキュメントのIDを取得します。

モデルを使用しても、モデルを編集することはできません。また、_@IgnoreExtraProperties_を使用することを忘れないでください

23
amrro

@iCediCeのソリューションを改善し、DocumentSnapshotおよびQuerySnapshotにメソッドを追加しました。

interface HasId {
    var id : String
}

inline fun <reified T : HasId> DocumentSnapshot.toObjectWithId(): T {
    return this.toObject(T::class.Java)!!.also {
        it.id = this.id
    }
}

inline fun <reified T : HasId> QuerySnapshot.toObjectsWithId(): List<T> {
    return this.documents.map {
        it.toObjectWithId<T>()
    }
}

そして使用法:

data class User(
    @get:Exclude
    override var id: String,
    ...
): HasId


val user = documentSnapshot.toObjectWithId<User>()
val users = querySnapshot.toObjectsWithId<User>()
7
comm1x

ここに私が問題を解決した方法があります。

data class Client(
    val name: String = "",
    val email: String = "",
    val phone: String ="",
    @get:Exclude var id: String = "") {
constructor():this("","","")
}

IDで@get:Excludeを使用して、保存時にIDがFirestoreに送信されないようにし、クライアントのリストを取得するときに実行します:

snapshot.documents.mapTo(list) {
            var obj = it.toObject(Client::class.Java)
            obj.id = it.id
            obj
        }

新しいオブジェクトのIDをドキュメント参照のIDに設定します。

6
ZerroShadows

QueryDocumentSnapshotに次のような拡張メソッドを作成することで解決しました。

_inline fun <reified T : HasId>QueryDocumentSnapshot.toObjectWithId(): T {
    val model = this.toObject(T::class.Java)
    model.id = this.id
    return  model
}
_

これで、次のようにマップできます(見た目はきれいできれいです):
myModelWithId = it.toObjectWithId<MyModel>()

これが機能するために、モデルで実装する必要がある単純なhasIdインターフェイスを作成しました。

_interface HasId{
    var id : String
}

@IgnoreExtraProperties
data class MyModel(
        @get:Exclude override var id : String    = "",
        val data                     : String    = "",

): Serializable, HasId
_
6
iCediCe

素晴らしいソリューション。 Firestoreがモデルに注釈を追加してこの問題を解決する方法を考案したようです。

できること:

_@DocumentId val documentId: String_

そして、FirestoreはtoObjectまたはtoObjectsを呼び出すときにそのフィールドを生成します。 Firestoreでドキュメントを.set()すると、このフィールドは除外されます。

1
Jeff Padgett

FirebaseでIDを取得してから、Firebaseで作成する前にオブジェクトのフィールドとして設定します。

    override fun addTodo(todo: Todo) =
    Completable.fromAction {
        val id = firestore
            .collection(COLLECTION_TODOS)
            .document()
            .id

        val newTodo = todo.copy(id = id)

        firestore
            .collection(COLLECTION_TODOS)
            .document(id)
            .set(newTodo)
    }
0
4ndro1d