Firebase Firestore - or Query

Firestore OR query

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.

Implementing OR in firestore query - Firebase firestore

Edit (November 2019)
Cloud Firestore now supports "IN" queries (announcement) which allows you to do a type of OR queries that look for documents with one of a few values on the same field.

For example for the query above:

db.collection('users')
.where('company_id', '==', companyId)
.where('role', 'in', ['Maker', 'Checker', 'Approver']);

Original answer

There is no "OR" query in Cloud Firestore. If you want to achieve this in a single query you will need a single field like maker_or_checker_or_approver: true.

Of course you can always do three queries and join them on the client.

Firebase Firestore Query based on filters

Based on your requirement, you can still use comparison values like code below:

Firebase Web Version 8:

db.collection("users")
.where("age", ">", "25")
.where("location", "==", "chicago")
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});

Firebase Web Version 9:

const q = query(collection(db, "users"), where("age", ">", "25"), where("location", "==", "chicago");

const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});

You can use comparison value as much as you want using these operators (<, <=, >, >=). By using multiple where queries, it provides you a query statement with logical AND query. The only limitation are for logical OR queries which on these documentation states:

Cloud Firestore provides limited support for logical OR queries. The in, and array-contains-any operators support a logical OR of up to 10 equality (==) or array-contains conditions on a single field. For other cases, create a separate query for each OR condition and merge the query results in your app.


UPDATE:

If you want to query 50 documents at the same time. You can query it using FieldPath.documentID() and "IN" query. See code below:

const docArray = [
// Array of Document IDs.
];

db.collection("users")
.where(firebase.firestore.FieldPath.documentId(), 'in', docArray)
.where("age", ">", "25")
.where("location", "==", "chicago")
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});

As I stated on my previous answer, this only works if the array is of less than 10 items (Firestore limitation). If you need more, you'll have to either batch the IDs, into smaller arrays and perform multiple queries. Check code I written below:

// Consists of 11 values
const docArray = [
'5fKmta1jgEiCQBZvSJ3Y',
'BubAGhg6IZbnzU70wdPf',
'FVEq9trqF2Hy8ROsAjeW',
'Nhz0pF2z3zw3aBcmnpqs',
'TYYDYyIiyhVuWp91h7OS',
'VDDiUGKkGnwrdo8jmDpb',
'VXnXEuNfrhUAM8UbZ2AH',
'XukTkr4XBey3yqAvFa3d',
'cSNI1NgHP8OEsDY66RBw',
'eCPc9F1bpS1qXD9WGKE2',
'eHdKQPhE7snnRjoWJzBK'
];
const chunkedArray = [];
const resArray = [];
var promises = [];

// Firestore query limit
size = 10;

for(var i = 0; i < docArray.length; i += size) {
chunkedArray.push(docArray.slice(i, i+size));
}

chunkedArray.forEach((chunked) => {
promises.push(
db.collection("users")
.where(firebase.firestore.FieldPath.documentId(), 'in', chunked)
.where("age", ">", "25")
.where("location", "==", "chicago")
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
resArray.push(doc.data());
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
})
);
})

Promise.all(promises).then(() =>
// Returns merged data from forEach
console.log(resArray)
);

You can also simply iterate the IDs, and get() each document individually. Look example code below:

docArray.forEach((docId) => {
promises.push(
db.collection("users")
.where(firebase.firestore.FieldPath.documentId(), '==', docId)
// .where("age", ">", "25")
// .where("location", "==", "chicago")
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
resArray.push(doc.data());
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
})
);
})

Promise.all(promises).then(() =>
// Returns merged data from forEach
console.log(resArray)
);

Cloud Firestore OR query

If you want to pass an array of strings to a filter to match any one of them for a given field, that's called an "in" query.

The API documentation for where() suggsets that you should use "whereIn" for that.

.where('owner', whereIn: users) 

From the documentation on in queries:

Use the in operator to combine up to 10 equality (==) clauses on the same field with a logical OR.

How do I Query Firebase Firestore for a field of type Geopoint in Flutter?

A Firestore query can only contain range conditions (>, >=, etc) on one value. So you can filter on either the latitude or longitude of the coords, but not on both in a single query.

If you want to perform geoqueries on Firestore at the moment, the common approach is to store an additional so-called geohash value in your document, which is a (rather magical) string value that combines latitude and longitude in a way that allows you to query them to filter on geographic blocks.

Sample Image

If you want to learn how this works, I recommend checking out this video on the topic: Querying Firebase and Firestore based on geographic location or distance.

If you want to implement this approach on top of Firestore, check out the documentation on implementing geoqueries on Firestore.

I also recommend checking out these previous questions on the topic:

  • How to run a geo "nearby" query with firestore?
  • How to filter Firestore collection data using function (for location distance filtering)
  • Is there a way to use GeoFire with Firestore?
  • Firestore multiple range query


Related Topics



Leave a reply



Submit