Imagine I have a collection in Firestore with objects of the following format:
{
/* ... */
ownerId: "id-1",
memberIds: [
"id-2",
"id-3",
"id-4"
]
}
How can I query Firestore for all documents where the string id-1
is present in the ownerId
field OR the memberIds
field?
I only found AND queries, like so:
return collection('whatever')
.where('memberIds', 'array-contains', 'id-1')
.where('ownerId', '==', 'id-1');
But those will only return me the documents where id-1
is included in both the ownerId
field and the memberIds
array.
I understand that I could perform multiple queries and join the results, but that would make pagination and ordering too much of a hassle to implement.
Since the release of the JS SDK Version 9.18.0 it is now possible to execute OR
queries.
So you can do as follows:
const colRef = collection(db, 'whatever')
const q = query(
colRef,
or(
where('memberIds', 'array-contains', 'id-1'),
where('ownerId', '==', 'id-1')
)
)
const querySnapshot = await getDocs(q)
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
It's not possible in Firestore to execute an OR query like the one you describe.
One solution is to denormalize your data (a very common approach in the NoSQL world) and add, to the document, an extra field which "concatenates" the two other fields, as follows:
{
/* ... */
ownerId: "id-1",
memberIds: [
"id-2",
"id-3",
"id-4"
],
ownersAndMemberIds: [
"id-1",
"id-2",
"id-3",
"id-4"
]
}
Then you can easily query the doc with
return collection('whatever')
.where('ownersAndMemberIds', 'array-contains', 'id-1');
Of course it requires that you maintain this array aligned with the other fields, but this is not difficult. Either you do it from your front-end when you update one of the two "main" fields, or through a Cloud Function which is triggered on any change to the doc.