Как получить идентификатор документа для документа Firestore с использованием классов данных kotlin
У меня есть класс данных kotlin
data class Client(
val name: String = "",
val email: String = "",
val phone: String ="") {
constructor():this("","","")}
У меня есть firestore, чтобы заполнить данные в классе просто отлично, однако я в затруднении, пытаясь понять, как получить идентификатор документа в классе данных, не устанавливая его в самом документе. Это возможно?
Ответы
Ответ 1
Да, возможно получить идентификатор без его сохранения, используя DocumentSnapshot
. Я попытаюсь привести здесь полные примеры.
Я создал общий класс модели для хранения id:
@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
, вы также можете получить идентификатор, как показано ниже:
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())
предоставит вам идентификатор документа в коллекции без сохранения идентификатора в документе.
Использование модели не позволит вам редактировать любую из ваших моделей и не забывайте использовать @IgnoreExtraProperties
Ответ 2
Я просто улучшил решение @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>()
Ответ 3
Вот как я решил проблему.
data class Client(
val name: String = "",
val email: String = "",
val phone: String ="",
@get:Exclude var id: String = "") {
constructor():this("","","")
}
Я использую @get: Исключить идентификатор, чтобы убедиться, что идентификатор не отправлен в Firestore при сохранении, а затем, когда вы выбираете список клиентов:
snapshot.documents.mapTo(list) {
var obj = it.toObject(Client::class.java)
obj.id = it.id
obj
}
Установка идентификатора нового объекта в идентификатор документа.
Ответ 4
Я решил это, создав метод расширения в 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
Ответ 5
Великолепные решения. Похоже, что Firestore предложил способ добавить аннотацию к вашей модели, чтобы решить эту проблему.
Вы могли бы сделать:
@DocumentId
val documentId: String
И тогда Firestore сгенерирует это поле при вызове toObject
или toObjects
. Когда вы .set()
документ в Firestore, это исключит это поле.
Ответ 6
Я просто извлекаю идентификатор из Firestore и устанавливаю его как поле на моем объекте, прежде чем создать его в 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)
}