In Firestore, how can you do a compound query involving a key in a map without creating an index for every key?

firestore join query
get all documents in collection firestore
firestore getall
firestore get document by id
firestore query
firestore where not equal
angular firestore query
flutter firestore query

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).

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);

Index types in Cloud Firestore, For each map field, Cloud Firestore creates one collection-scope ascending index Single-field indexes with collection group scope are not maintained by default. If you attempt the query above without first creating the required index, Cloud Cloud Firestore uses composite indexes to support compound queries not  You can also deploy indexes with the Firebase CLI . To get started, run firebase init firestore in your project directory. During setup, the Firebase CLI generates a JSON file with the default indexes in the correct format. Edit the file to add more indexes and deploy it with the firebase deploy command. If you only want to deploy indexes, add

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).

Perform simple and compound queries in Cloud Firestore, You can combine array-contains with in but not with array-contains-any . Compound queries. You can also chain multiple where() methods to create more specific  Cloud Firestore can merge the indexes for simple equality filters to build the composite indexes needed for larger equality queries. You can reduce indexing costs by identifying situations where you can take advantage of index merging. For example, imagine a restaurants collection for a restaurant rating app: collections_bookmark restaurants

Now Firestore allows the array-contains operator. If you want to filter documents which contain specific value, try this.

First, change Map field to Array field.

Post {
    title: ..
    ...
    categories: [
        cats,
        puppies
    ]
}

Second, use array-contains and orderBy for each different fields.

let query = db.collection(`/posts`)
    .where('categories', 'array-contains', 'cats')
    .orderBy('createdAt')
    .startAfter(lastDate)
    .limit(5);

You can check the official document about array-contains operator from here.

In Firestore: how can you do a compound query involving a key in a , In Firestore, how can you do a compound query involving a key in a map without creating an index for every key? For example In my case, it isn't feasible to create composite indices for every category since categories are  Cloud Firestore provides powerful query functionality for specifying which documents you want to retrieve from a collection or collection group. These queries can also be used with either get () or addSnapshotListener (), as described in Get Data and Get Realtime Updates. Note: While the code samples cover multiple languages, the text

Update and Customize Queries on Your Cloud Firestore Data for , In the previous post, we learned about how to enable Firestore in the If you are not familiar with how to create a new intent, check out part 1 of this Firestore is unable to perform the query above, but you can tell it to create an index that involves all A button that says 'Get it on, Google Play', and if clicked. When you send a database a query, the database can use an index to quickly look up the locations of the items you requested. This page describes the two types of indexes that Cloud Firestore uses, single-field indexes and composite indexes .

Getting Started With Cloud Firestore for iOS, By making it easy to store and persist data in the cloud and take care of each. You will learn how to work with Firestore document references, as well as index queries with compound sorting and filtering, allowing you to combine but instead sets of key/value pairs that you would find within documents. Cloud Firestore provides powerful query functionality for specifying which documents you want to retrieve from a collection or collection group. These queries can also be used with either get () or addSnapshotListener (), as described in Get Data and Get Realtime Updates. Note: While the code samples cover multiple languages, the text

firestore, In Firestore, documents are sets of key-value pairs, and collections are groups of documents. A Firestore Creating a ref does not involve any network traffic. Call its Data method to obtain the entire document contents as a map. To get all the documents in a collection, you can use the collection itself as a query. Firestore is a real time database that stores collections and documents. A collection stores documents and a document is made up of json. There’s no predefined data structure, you can add and

Cloud Firestore iOS Codelab, In this extended codelab, you will build a restaurant recommendation app powered by Cloud how document structure in Firestore shapes your database queries. If you do not have Node installed, you can do so by downloading the installer from this page. All of the code in this workshop and sample app uses Swift 4.2. Index building errors. You might encounter index building errors when managing composite indexes and single-field index exemptions. An indexing operation can fail if Cloud Firestore encounters a problem with the data it's indexing. Most commonly, this means you hit an index limit. For example, the operation may have reached the maximum number

Comments
  • It looks little odd, but it is the only workaround currently.
  • Not to mention that this only work for two param, so if you were to add another parameter to the query this would not work. I wish Firebase adds the capability. But this was a great solution for the question thanks
  • Hey @Frank, thanks for the answer. You are correct in simple cases, however the issue arrises when using the orderBy clause, which is required in order to be able to use startAfter for paginating the query. It seems that as soon as you add orderBy, you need to create a composite index, but I'm hoping there is another way
  • Aha... got it. That makes sense. And unfortunately I don't think there's any automatic index creation for that. The number of combinations would explode and go over the maximum number of indexes quickly. Sorry about that.
  • Hi @FrankvanPuffelen how do we write the query for db.collection('posts').where('roles.${uid}', '==', 'EDITOR' || 'VIEWER')?
  • @choopage-JekBao as explained in the documentation (bottom page of the link provided in the answer of this question) Logical OR queries. In this case, you should create a separate query for each OR condition and merge the query results in your app