I am building a 1-to-1 chat application with Firestore and Javascript (vue.js).
I have a conversation and a message document defined as follows:
.collection("coversation").doc()
conversation: {
participantsArray: ["id1", "id2"],
participants: {
id1: {
/* details like avatar & name */
},
id2: {
/* details like avatar & name */
}
}
}
.collection("coversation").doc("foo").collection("messages").doc()
message: {
message: "foo"
}
This is great, so I can now query for all conversations of a specific user like so:
db.collection('conversations').where("participantsArray", "array-contains", userId)
The issue I am having now is the following:
I want to query for a specific conversation, like so:
db.collection('conversations')
.where("participantsArray", "array-contains", userId)
.where("participantsArray", "array-contains", chatpartnerId)
But this does not work since double "array-contains" is not allowed and throws an error message.
What works for me for now is to make two calls like so:
db.collection('conversations')
.where(`participantsArray`, '==', [userId, chatpartnerId])
db.collection('conversations')
.where(`participantsArray`, '==', [chatpartnerId, userId])
and then check if any of these queries returns a conversation. If so, I use that conversation to add a message, otherwise I create a new conversation.
It works, but it's a bunch of code and quite inefficient.
So my question would be:
PS: Before, I used to query on the objects in the participants object like so:
db.collection("conversations").where(`participants.${userId}.id`, "==", userId)
This was the proposed way to query before "array-contains" existed - but when combined with orderBy I would have to create an index for each user, which is not really an option.
With the in query, you can query a specific field for multiple values (up to 10) in a single query. You do this by passing a list containing all the values you want to search for, and Cloud Firestore will match any document whose field equals one of those values.
Firebase introduced an array-contains operator that can be used with where to query array fields. It will return all documents that contain a the provided value in the array. Currently, this is only supported with one value, so don't try chaining more than one of these in a single query. const col = firestore.
A QuerySnapshot contains zero or more QueryDocumentSnapshot objects representing the results of a query. The documents can be accessed as an array via the docs property or enumerated using the forEach method. The number of documents can be determined via the empty and size properties.
The array [1, 2, 3] has elements equal to the first three elements of [1, 2, 3, 1] but is shorter in length. Up to 1,048,487 bytes (1 MiB - 89 bytes). Only the first 1,500 bytes are considered by queries.
I found a way around how to query for a single conversation.
Since I have both (1) the participants with the details in an "participants" object and (2) the participant ID's in "participantsArray", I can query for a single conversation as follows:
db.collection('conversations')
.where(`participants.${userId}.id`, "==", userId)
.where(`participants.${chatPartnerId}.id`, "==", chatPartnerId)
So I am happy for now. However, the three questions remain, so if someone can answer them properly their answer would be very valuable :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With