I am trying query a number of documents in different collections with array-contains-any
, by using Promise.all()
to get all the documents at once.
I’ve checked whether the path is correct, whether the documents exist, whether the key
exists in the document and everything is ok.
The querySnapshots
and snapshots
have no data retrieved. At some point of the log says: “_size”:0,”_materializedDocs”:null.
let promises = [] depIds.forEach(id => { const prodIds = groupedProducts[id].reduce((acc, val) => [...acc, val.prodId], []); console.log("All prodIds: ", prodIds, "; also id is: ", id); promise = admin.firestore() .collection('Products') .doc('Departments') .collection(id) .where('key', 'array-contains-any', prodIds) .get(); promises.push(promise) }) const querySnapshots = await Promise.all(promises); const snapshots = querySnapshots.map(doc => { console.log("docs: ", JSON.stringify(doc)) return doc; });
So my questions are:
Is it possible to query as above?
How to get the actual data after the
Promise.all()
command?
I appreciate any help!
Advertisement
Answer
If the key
field in your document is a string, you should be using the in
operator.
The array-contains-any
operator checks if any of the values you have given are in the array of the named field. As key
is a string, this operator will always return no results.
To get all documents where key
matches a given ID, while also ensuring that you can fetch more than 10 documents at a time, you can use:
/** splits array `arr` into chunks of max size `n` */ function chunkArr(arr, n) { if (n <= 0) throw new Error("n must be greater than 0"); return Array .from({length: Math.ceil(arr.length/n)}) .map((_, i) => arr.slice(n*i, n*(i+1))) } /** Fetch all given product IDs (if they exist) for the given department */ fetchDepartmentProducts(depId, prodIdList) { const prodIdListInBatches = chunkArr(prodIdList, 10); const departmentCollectionRef = admin.firestore() .collection('Products') .doc('Departments') .collection(depId); const promises = prodIdListInBatches.map((prodIdListBatch) => { return departmentCollectionRef .where('key', 'in', prodIdListBatch) .get(); }); return Promise.all(promises) // waits for all get requests .then((allQuerySnapshots) => { // flatten the found documents of the query snapshots into one array const allDocSnapshots = []; allQuerySnapshots.forEach((querySnapshot) => allFoundDocSnapshots.push(...querySnapshot.docs) ); return allDocSnapshots; }); }
Working this into your code, gives:
const promises = depIds.map((id) => { const prodIds = groupedProducts[id].map((product) => product.prodId); return fetchDepartmentProducts(id, prodIds); } const productsByDepartment = await Promise.all(promises); productsByDepartment.forEach((docsInDeparment, i) => { console.log(`Found ${docsInDeparment.length} products in department #${depId[i]}.`); });