CEO tech4lifeapps
CEO tech4lifeapps

Reputation: 895

Android/Kotlin: How to get a DocumentReference to a document in a sub-collection in Firestore?

I have a document("Cards")-sharing application written in Kotlin using a Firestore database. Users can create and share multimedia-messages that are stored in a sub collection like this:

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

cardDocID gets generated automatically when a document is stored.

I have no problem storing messages, retrieving data and displaying it in a "CardViewActivity" using RecyclerView and CardView(s) supported by the Groupie Library.

My problem: I want to implement a Delete function triggered by a onItemLongClick event on any message item displayed. In order to do that, I need to get hold of a DocumentReference, similar to this:

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

How can I get that cardDocID in my "CardViewActivity"? I use the following code to get the data:

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)
        }
}

Upvotes: 2

Views: 4758

Answers (2)

CEO tech4lifeapps
CEO tech4lifeapps

Reputation: 895

Here's how I finally solved my problem:

  1. Add a new Type Parameter (cardDocumentID: String) to class "Card", like this:
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. In function addCardsListener (*see note below), get a reference forEach document from the querySnapshot. This reference allows us to get hold of cardDocumentID. We then update our item by including that cardDocumentID. Finally, we add the item to our list "items".
    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. Now our OnItemLongClickListener can get hold of cardDocumentID needed to build a reference to the Document (DocumentReference) and finally delete the document.
    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
    }

P.S. The addCardsListener is called in the onCreate section of the Activity that displays the Cards.

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

Upvotes: 4

Doug Stevenson
Doug Stevenson

Reputation: 317467

You will either have to:

  1. Remember that ID on the client right after you add it
  2. Perform a query for that document using what you already know about its contents.

In either case, you need to know something about a document in order to find it. Usually it's best to record the ID in a place where you can find it again. Sometimes that might be back into the database in a place where another query will find it for you.

Upvotes: 0

Related Questions