【问题标题】:Android/Kotlin: How to get a DocumentReference to a document in a sub-collection in Firestore?Android/Kotlin:如何获取对 Firestore 子集合中文档的 DocumentReference?
【发布时间】:2020-01-15 19:30:49
【问题描述】:

我有一个使用 Firestore 数据库用 Kotlin 编写的文档(“卡片”)共享应用程序。用户可以创建和共享存储在子集合中的多媒体消息,如下所示:

collection("users").document(userId).collection("messages").document(cardDocID)

cardDocID 会在存储文档时自动生成。

我使用 Groupie 库支持的 RecyclerView 和 CardView(s) 存储消息、检索数据并将其显示在“CardViewActivity”中没有问题。

我的问题:我想在显示的任何消息项上实现由 onItemLongClick 事件触发的删除函数。为此,我需要获取一个 DocumentReference,类似于:

val currentDocRef: DocumentReference =
                firestoreInstance.document("users/$uid/messages/$cardDocID")

如何在“CardViewActivity”中获取 cardDocID? 我使用以下代码获取数据:

messagesListenerRegistration = addCardsListener(this, userId, this::updateRecyclerView)


 fun addCardsListener(context: Context, selectedUser: String, onListen: (List<Item>) -> Unit
): ListenerRegistration {
    return firestoreInstance.collection("users").document(selectedUser).collection("messages")
        .orderBy("time")
        .addSnapshotListener { querySnapshot, firebaseFirestoreException ->

            if (firebaseFirestoreException != null) {
                Log.e("FIRESTORE", "Cards listener error.", firebaseFirestoreException)
                return@addSnapshotListener
            }

            val items = mutableListOf<Item>()
            querySnapshot!!.documents.forEach {

                // if (it.id != FirebaseAuth.getInstance().currentUser?.uid) // to filter the currentUser
                items.add(CardItem(it.toObject(Card::class.java)!!, context))
            }
            onListen(items)
        }
}

【问题讨论】:

    标签: android firebase kotlin google-cloud-firestore


    【解决方案1】:

    您必须:

    1. 添加后立即记住客户端上的 ID
    2. 使用您已经知道的内容对该文档执行查询。

    在任何一种情况下,您都需要对文档有所了解才能找到它。通常最好将 ID 记录在可以再次找到的地方。有时,它可能会回到数据库中另一个查询会为您找到它的地方。

    【讨论】:

    • 第 1 点:您能否详细说明一下,也许可以提供一个示例?为什么要记住“在客户端”以及如何记住?
    • 这完全取决于你来决定什么是最好的。您在问题中还没有真正说出足够的内容来了解​​您的应用程序的要求是什么。有十几种方法可以在应用程序中存储数据。共享首选项,sqlite,直接写本地存储。其中任何一个都可以存储一小段文本。
    • 子集合中组织的文档不需要存储自己的 ID。我认为您可能误解了 Cloud Firestore 的工作原理。如果客户端应用需要读取或删除单个文档,则它需要从其自己的存储或生成该 ID 的查询中获取该文档的 ID。
    • 那么,我的 OnItemLongClickListener 需要查询我的数据库以查找与我当前单击的项目完全匹配的项目,以便找到其文档 ID?
    • 如果您不打算将文档的 ID 存储在任何地方,那么可以。但没有人真正做到这一点。人们存储 ID。
    【解决方案2】:

    这是我最终解决问题的方法:

    1. 向“Card”类添加一个新的类型参数(cardDocumentID:String),如下所示:
    data class Card(
        val time: Date,
        val author: String,
        val title: String,
        val subtitle: String,
        val story: String,
        val storyPicturePath: String?,
        val voiceMessagePath: String?,
        val senderName: String,
        var cardDocumentID: String
    
    ) {
        constructor() : this(Date(0), "", "", "", "", null, null, "", "")
    }
    
    1. 在函数 addCardsListener 中(*请参见下面的注释),从 querySnapshot 中获取每个文档的引用。此引用允许我们获取 cardDocumentID。然后,我们通过包含该 cardDocumentID 来更新我们的项目。最后,我们将项目添加到我们的列表“项目”中。
        fun addCardsListener(
            context: Context, selectedUser: String, onListen: (List<Item>) -> Unit
        ): ListenerRegistration {
            return firestoreInstance.collection("users").document(selectedUser).collection("messages")
                .orderBy("time")
                .addSnapshotListener { querySnapshot, firebaseFirestoreException ->
    
                    if (firebaseFirestoreException != null) {
                        Log.e("FIRESTORE", "Cards listener error.", firebaseFirestoreException)
                        return@addSnapshotListener
                    }
    
                    val items = mutableListOf<Item>()
                    querySnapshot!!.documents.forEach {
    
                        val ref = it.reference
                        val cardDocumentID = ref.id
                        Log.d("FIRESTORE", "cardDocumentID: " + cardDocumentID)
    
                        // we need to add this ID to our Card item
                        var item = (it.toObject(Card::class.java)!!)
                        item.cardDocumentID = cardDocumentID
    
                        items.add(CardItem(item, context))
                    }
                    onListen(items)
                }
        }
    
    1. 现在我们的 OnItemLongClickListener 可以获取构建对文档的引用 (DocumentReference) 并最终删除文档所需的 cardDocumentID。
        private val onItemLongClick = OnItemLongClickListener { item, view ->
    
            if (item is CardItem) {
                if (userName == loggedInUser) {
    
                    val uid = FirebaseAuth.getInstance().currentUser?.uid
                    val cardDocID = item.card.cardDocumentID
                    val currentDocRef: DocumentReference =
                        firestoreInstance.document("users/$uid/messages/$cardDocID")
    
                    currentDocRef.delete()
    
                 } else {
                    Snackbar.make(view, "Login as " + userName + " to delete this card", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show()
                }
            }
            true
        }
    

    附: addCardsListener 在显示卡片的 Activity 的 onCreate 部分中调用。

        messagesListenerRegistration =
                addCardsListener(this, userId, this::updateRecyclerView)    
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-13
      相关资源
      最近更新 更多