Fire Beast

How to implement tag filtering in Firestore

If you're looking to add the tagging feature to your app that uses Firestore, then I have good and bad news for you. The good news is that can add basic tag query in minutes, and there are at least a couple ways to do that, but the bad news is that each of these approaches has limitations, and not every scenario is possible.

In this article, we'll look at approaches to each scenario and its limitations.

Getting documents from Firestore with a specific tag

Let's start with the basic scenario where you need to query all documents that has a specific tag.

You can keep tags as a list of strings and use array-contains where filter to query it:

db.collection('jobs')
  .where('tags', 'array-contains', 'firebase')

You can also easily combine it with ordering condition after adding the required index:

db.collection('jobs')
  .where('tags', 'array-contains', 'firebase')
  .orderBy('publishedAt', 'desc')

But if you'll try to query collection using multiple array-contains:

db.collection('jobs')
  .where('tags', 'array-contains', 'firebase')
  .where('tags', 'array-contains', 'react')
  .orderBy('publishedAt', 'desc')

Then you'll get an error:

FirebaseError: Invalid query. You cannot use more than one 'array-contains' filter.

Luckily, now, Firestore has a solution for that.

Getting documents from Firestore with any of given tags

If you need to query documents that have at least one of specified tags, then you can use the latest addition to Firestore, array-contains-any where filter:

db.collection('jobs')
  .where('tags', 'array-contains-any', ['firebase', 'react'])

Just like array-contains, array-contains-any also could be used with ordering condition:

db.collection('jobs')
  .where('tags', 'array-contains-any', ['firebase', 'react'])
  .orderBy('publishedAt', 'desc')

However, if you want to query documents that have all of given tags, not any, then you are out of luck because there's no array-contains-all.

You still can do that, but to make it happen, you'll need to change the way you store the tags.

Getting documents with all of given tags

To query documents that have all of the given tags, you'll need to change the way you store those. Instead of the array of strings, you'll need to use the map:

[
  'typescript',
  'firebase',
  'react'
]
// →
{
  typescript: true,
  firebase: true,
  react: true
}

So that you could query using regular where filter:

db.collection('jobs')
  .where('tags.firebase', '==', true)
  .where('tags.react', '==', true)

This way, you can query simultaneously by any number of tags.

However, if you would try to sort the result:

db.collection('jobs')
  .where('tags.firebase', '==', true)
  .where('tags.react', '==', true)
  .orderBy('publishedAt', 'desc')

Then you'll get an error:

FirebaseError: The query requires an index.

To make it work you'll have to add compound index on publishedAt, tagsMap.react and tagsMap.firebase which means you'll need to add index to all possible combinations making it virtually impossible.

The only option is to implement sorting on the client-side unless you have too many documents in your collection to make it feasible. If so, I'm afraid you're out of options to expect that use running a server with an Elastic Search instance (or something similar) or using SaaS service such as Algolia.


Tag filtering with Firestore is an easy task unless you need to query documents that have all of the given tags. Then you'll have to choose between client-side sorting and running an instance with a search engine or using 3rd-party service.