Reputation: 145
Let's say I have a collection of 2000 documents with fields id, age, location in cloud firestore.
On client side(nodejs), I have 50 ids and want to perform a query on the firestore only for these 50 ids and should satisfy the conditions like age>25, location=chicago. I don't want to read all 50 documents. Want to read the documents from these 50 ids which satisfies the conditions I mentioned (The resulting documents could be less than 50) trying to reduce read operations. Is it possible to do this? Looking at the documentation I see there is in operator but my understanding is it only supports for 10 comparison values. Is it possible to query as per my requirement?
While creating the documents, I can adjust the documentId to be the field id if that makes the query possible.
Upvotes: 1
Views: 2992
Reputation: 4069
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 logicalOR
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)
);
Upvotes: 4