webentwicklung-frage-antwort-db.com.de

Wie erhalte ich die Dokument-ID für ein Firestore-Dokument mit Kotlin-Datenklassen?

Ich habe eine Kotlin-Datenklasse 

data class Client(

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

Ich habe Firestore damit bestückt, die Daten gut in die Klasse einzugeben. Ich versuche jedoch herauszufinden, wie ich die Dokument-ID in die Datenklasse bekomme, ohne sie im Dokument selbst festlegen zu müssen. Ist das möglich? 

7
ZerroShadows

Ja, es ist möglich, eine ID zu erhalten, ohne sie zu speichern, indem Sie DocumentSnapshot verwenden. Ich werde versuchen, hier vollständige Beispiele zu erstellen.

Ich habe eine allgemeine Model-Klasse für die ID erstellt: 

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

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

Dann erweitern Sie es mit jedem Modell, Sie müssen nichts implementieren: 

public class Client extends Model

Wenn ich hier eine Liste von Clients habe, versuche ich die Liste abzufragen, um nur Clients mit age == 20 zu erhalten: 

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 {

                }
            }
        });

Und wenn Sie EventListener verwenden, können Sie die ID auch wie folgt erhalten: 

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()) ruft die ID des Dokuments in der Sammlung auf, ohne die ID im Dokument zu speichern.

Mit Model können Sie keines Ihrer Modelle bearbeiten. Vergessen Sie nicht, @IgnoreExtraProperties zu verwenden.

17
amrro

Ich habe es gelöst, indem ich eine Erweiterungsmethode für QueryDocumentSnapshot erstellt habe:

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

Jetzt kann ich wie folgt abbilden (was ich schön und sauber finde):
myModelWithId = it.toObjectWithId<MyModel>()

Damit dies funktioniert, habe ich eine einfache hasId-Schnittstelle erstellt, die das Modell implementieren muss:

interface HasId{
    var id : String
}

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

): Serializable, HasId
6
iCediCe

So habe ich das Problem gelöst. 

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

Ich verwende @get: Exclude für die ID, um sicherzustellen, dass die ID beim Speichern nicht an Firestore gesendet wird. Führen Sie beim Abrufen der Liste der Clients Folgendes aus:

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

Festlegen der ID des neuen Objekts auf die ID der Dokumentreferenz.

4
ZerroShadows

Ich habe gerade die Lösung von @iCediCe verbessert und Methoden zu DocumentSnapshot und QuerySnapshot hinzugefügt.

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>()
    }
}

Und Verwendung:

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


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

Großartige Lösungen. Anscheinend hat Firestore eine Möglichkeit gefunden, Ihrem Modell eine Anmerkung hinzuzufügen, um dieses Problem zu lösen.

Du könntest es tun:

@DocumentId val documentId: String

Und dann generiert Firestore dieses Feld, wenn Sie toObject oder toObjects aufrufen. Wenn Sie das Dokument in Firestore .set(), wird dieses Feld ausgeschlossen.

1
Jeff Padgett

Ich habe gerade eine ID aus Firestore abgerufen und sie als Feld für mein Objekt festgelegt, bevor ich sie in Firebase erstelle:

    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