我有kotlin数据类
data class Client(
val name: String = "",
val email: String = "",
val phone: String ="") {
constructor():this("","","")}
我让firestore将数据填充到类中,但是我不知道如何将文档id放入数据类而不必在文档本身中设置它。这可能吗?
答案 0 :(得分:19)
是的,使用DocumentSnapshot
可以在不存储ID的情况下获取ID。我将尝试在这里建立完整的例子。
我创建了一个通用的Model类来保存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
,您还可以获得如下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
答案 1 :(得分:6)
以下是我解决问题的方法。
data class Client(
val name: String = "",
val email: String = "",
val phone: String ="",
@get:Exclude var id: String = "") {
constructor():this("","","")
}
我使用@get:在id上排除以确保在保存时不会将id发送到Firestore,然后在获取客户端列表时执行:
snapshot.documents.mapTo(list) {
var obj = it.toObject(Client::class.java)
obj.id = it.id
obj
}
将新对象的id设置为文档引用的id。
答案 2 :(得分:5)
我通过在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
答案 3 :(得分:4)
我刚刚改进了@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>()
答案 4 :(得分:3)
很好的解决方案。看起来Firestore想出了一种向模型添加注释来解决此问题的方法。
您可以这样做:
@DocumentId
val documentId: String
然后,Firestore将在调用toObject
或toObjects
时生成该字段。当您.set()
在Firestore中的文档时,它将排除此字段。
答案 5 :(得分:0)
在Firebase中创建ID之前,我只是从Firestore中获取ID并将其设置为对象上的字段:
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)
}