In Firestore, how can you do a compound query involving a key in a map without creating an index for every key?
For example, consider a collection which holds blog posts, and each blog post has categories.
Post { title: .. ... categories: { cats: true puppies: true } }
In order to query posts in a particular category in a paginated way, we would do something like this:
let query = db.collection(`/posts`) .where(`categories.${categoryId}`, '==', true) .orderBy('createdAt') .startAfter(lastDate) .limit(5);
But it seems that this would require a composite index (categories.<categoryId>
and createdAt
) for every single category. Is there any way around this?
In my case, it isn't feasible to create composite indices for every category since categories are user-generated, and could easily exceed 200 (the limit for composite indices in Firestore).
Cloud Firestore does not support the equivalent of SQL's update queries.
Composite indexes A composite index stores a sorted mapping of all the documents in a collection, based on an ordered list of fields to index. Note: You can have at most one array field per composite index. Cloud Firestore uses composite indexes to support queries not already supported by single-field indexes.
This is doable by setting the value of each category to what you want to sort on. Firestore has a guide that covers this.
Post { title: .. ... categories: { cats: createdAt puppies: createdAt } } let query = db.collection(`/posts`) .where(`categories.${categoryId}`, '>', 0) .orderBy(`categories.${categoryId}`) .startAfter(lastDate) .limit(5);
As far as I know Firestore should auto-generate those indexes. From the documentation page on arrays, lists, and sets:
Consider this alternative data structure, where each category is the key in a map and all values are true:
// Sample document in the 'posts' collection { title: "My great post", categories: { "technology": true, "opinion": true, "cats": true } }
Now it's easy to query for all blog posts within a single category:
// Find all documents in the 'posts' collection that are // in the 'cats' category. db.collection('posts') .where('categories.cats', '==', true) .get() .then(() => { // ... }); )
This technique relies on the fact that Cloud Firestore creates built-in indexes for all document fields, even fields in a nested map.
While the lefthand-side of your where condition may be variable, that doesn't change the fact that these indexes should auto-generated (as far as I can see).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With