I am writing a function to query a Firestore database collection for documents that have only certain properties. The filters is defined as an array of "key, value" pairs. eg:
[
["Colour", "green"],
["Colour", "blue"],
["Greeting", "hello"]
]
This array can be of any length, and I am trying to get every document in the database that does not have values listed in the filter array.
I can do this by using:
await db.collection("database")
.where("Colour", "!=", "blue")
.where("Colour", "!=", "green")
.where("Greeting", "!=", "hello")
.get()
My issue is that the filter can be any length, so I cannot write the query to have a set number of .where()
methods. Is there any way in JavaScript that I can dynamically add methods to a query like shown above (not knowing how many methods I need to add)?
My workaround right now is just to query the entire database, then sort it using Javascript filter functions, but I would like to only have to query the database for the values needed.
Alternatively, are there any other Firestore queries that could complete this filter? I was looking at the docs, but the way my filter is set up with key/value pairs that could be repeated or undefined, it did not seem that any of the complex query methods would work.
Assuming that you are building an array full of only excluded key-value pairs and the values you are excluding are properly indexed, we can start off defining some constants:
const collectionRef = db.collection("database");
const excludedKeyValuePairs = [
["Colour", "green"],
["Colour", "blue"],
["Greeting", "hello"],
]
Now we have those, we can build the query using Array#reduce.
const query = excludedKeyValuePairs
.reduce(
(query, [key, value]) => query.where(key, "!=", value), // appends the new constraint, returning the new query object
collectionRef
);
const querySnapshot = await query.get();
However, if you can use the newer modular Firestore SDK, you can also achieve the same result using:
import { getFirestore, getDocs, collection, query, where } from "firebase/firestore";
const db = getFirestore();
const collectionRef = collection(db, "database");
const constraints = [
where("Colour", "!=", "green"),
where("Colour", "!=", "blue"),
where("Greeting", "!=", "Hello")
// elements can also be added or removed using standard array methods as needed.
]
// OR const constraints = excludedKeyValuePairs.map(([key, value]) => where(key, "!=", value))
const querySnapshot = await getDocs(query(collectionRef, ...constraints));