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