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:
- Is there a better way to do this?
- How to do "array-contains" to check for multiple items?
- I have both a participantsArray and a participants field because I did not figure out how to do "array-contains" on an array of objects. Is there a way or should I keep both fields?
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.