如何使用 kotlin 数据类获取 Firestore 文档的文档 ID
Posted
技术标签:
【中文标题】如何使用 kotlin 数据类获取 Firestore 文档的文档 ID【英文标题】:How do I get the document ID for a Firestore document using kotlin data classes 【发布时间】:2018-04-10 05:48:36 【问题描述】:我有 kotlin 数据类
data class Client(
val name: String = "",
val email: String = "",
val phone: String ="")
constructor():this("","","")
我有 Firestore 将数据填充到类中就好了,但是我不知道如何将文档 id 放入数据类中,而不必在文档本身中设置它。这可能吗?
【问题讨论】:
【参考方案1】:是的,可以使用DocumentSnapshot
在不存储的情况下获取 id。我将尝试在这里构建完整的示例。
我创建了一个通用模型类来保存 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.
QueryDocumentSnapshot document = change.getDocument();
Client client = document.toObject(client.class).withId(document.getId());
// you can apply your actions...
);
documentSnapshot.getId())
将获取集合中 Document 的 id,而不会将 id 保存到文档中。
使用模型不会让您编辑任何模型,不要忘记使用@IgnoreExtraProperties
【讨论】:
我要做的是将 id 放入我的 Client 模型中,以便我可以在列表视图中单击时引用。我没有看到任何保留对它的引用的方法。 那么你的问题与firebase无关! (也取决于您的回答。)您可以创建任何您想要的自定义构建器。 这能回答你的问题吗? 嘿,你能说一下在javascript中获取满足某些约束(我们可以使用查询)的文档ID吗? 您好@DivyaGalla 抱歉回复晚了。但我想这会对你有所帮助,并且有什么限制? firebase.google.com/docs/reference/js/…【参考方案2】:这是我解决问题的方法。
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。
【讨论】:
【参考方案3】:我通过在 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
【讨论】:
太棒了!帮了我很多。此外,Kotlin 如何让您的生活变得如此轻松,这让我仍然感到惊讶......【参考方案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>()
【讨论】:
我不确定你是如何做到这一点的。为了使 firebase (de)serializer 工作,您的User
类将需要一个无参数构造函数。 id
是一个不可为空的 var 会破坏这种能力?【参考方案5】:
我之前只是从 Firestore 获取一个 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)
【讨论】:
【参考方案6】:很好的解决方案。看起来 Firestore 想出了一种方法来为您的模型添加注释来解决这个问题。
你可以这样做:
@DocumentId
val documentId: String
然后 Firestore 将在调用 toObject
或 toObjects
时生成该字段。当您在 Firestore 中.set()
文档时,它将排除该字段。
【讨论】:
这是在哪里记录的? firebase.google.com/docs/reference/kotlin/com/google/firebase/… 感谢您的链接! 这应该是公认的答案。 似乎这个字段需要有一个默认值,否则,我们会得到错误 - 无法反序列化对象。类“X”没有定义无参数构造函数。【参考方案7】:2021 年使用 Kotlin: 像这个例子一样将它包含到你的数据类中的最简单方法:
@Parcelize
data class Level(
var name:String?=null,
var order:Int=0,
var parentCycleId:String?=null,
var totalExercices:Int=0,
@DocumentId
val id: String?=null,
):Parcelable
id 将由 firestore 数据库自动分配
我通过这样的监听器获取数据:
firestoreDatabase.collection("levels")
.whereEqualTo("parentCycleId",sharedData.getSelectedCycle().id!!)
.orderBy("order")
.addSnapshotListener(object : EventListener<QuerySnapshot>
@SuppressLint("NotifyDataSetChanged")
override fun onEvent(value: QuerySnapshot?, error: FirebaseFirestoreException?)
if (error != null)
Log.e("ZEADEV",error.message.toString())
return
for (dc: DocumentChange in value?.documentChanges!!)
if (dc.type == DocumentChange.Type.ADDED)
val retrievedLevel: Level = dc.document.toObject(Level::class.java)
levelList.add(retrievedLevel)
levelAdapter.notifyDataSetChanged()
)
并且检索到的数据包含文档ID,您可以通过此示例的校准来获取它
retrievedLevel.id
【讨论】:
以上是关于如何使用 kotlin 数据类获取 Firestore 文档的文档 ID的主要内容,如果未能解决你的问题,请参考以下文章
如何在 android 中获取 XML 响应字符串以及 Kotlin 数据模型?