如何使用 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&lt;MyModel&gt;()

为此,我制作了一个模型需要实现的简单 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 将在调用 toObjecttoObjects 时生成该字段。当您在 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 数据模型?

如何在 Kotlin 中获取泛型参数类

如何在kotlin中的匿名类中获取父类[重复]

如何在Android上的Kotlin类中使用上下文

如何在 kotlin android 中使用 volley 获取 json

如何使用数据类在 Kotlin 中解决“无法编写 JSON:无限递归 (***Error)”?