Firestore Get All Documents Where a Specific Field Exists or Does Not Exist

In Firebase’s Firestore database, you may want to query and get all the documents in a collection that either contains a specific field (or key) or does not contain a specific field (or key). By contain, I mean all the documents where a specific field either exists, or doesn’t exists.

Query and get all documents that DO NOT have a certain field

Let’s first tackle this problem. Imagine you wanted to query and retrieve all the documents from the collection posts that do not have the tags field. This is not possible in Firestore currently. We should understand why.

In Firestore, all queries are served off indexes for performance reasons. Most of these indexes on single columns are automatically created for us, which is why when we get started, we don’t realise it. So if we create documents in the posts collection with fields like title, description, comments, tags, created_by, created_at and then query on the collection with a firestore.collection('posts').where('created_by', '==', 'xxx'), then behind the scenes, firebase uses an “automatically maintained” index which is used to serve the results. This fetching process is real fast because of the indexes.

So if a document does not have a specific field, that means it never made it to the index for that field. Hence it won’t be returned when we performed a collection.where('field', '==', 'xxx').

Query and Retrieve all documents that DO have a specific field

This is possible, but in a way that may feel weird to some. From the Firestore documentation on order and limit data:

Note: An orderBy() clause also filters for existence of the given field. The result set will not include documents that do not contain the given field.

So if you want to query all the posts documents that do not contain the tags field, all you have to do is this:

firestore.collection('posts').orderBy('tags') // or
firestore.collection('posts').orderBy('tags', 'desc')

You will have a single index automatically available on tags, so it’ll just work!

In some cases like when you’re trying to query a collection group for a similar use-case, you will have to manually or explicitly create an index under the collection group scope. This is because firebase does not automatically create composite indexes and collection group scope indexes. The best way to do it is, let your code run and execute the query which will eventually cause the firebase SDK to throw an error due to a missing index. The error message will contain a link to create the index manually, so just copy paste that link in the browser and make it work.

The other option is going to the Firebase console and doing it in Firestore Database > Indexes by yourself. Do this if you have a good understanding of single indexes, composite indexes, collection groups and index modes.

Bonus: There’s an alternate “hack” to the orderBy solution. To check for documents that do contain a field, you could do a not "value" check, for instance a not null:

firestore.collection('posts').where('tags', '!=', null)

The != check excludes documents where the specified field does not exist but it also excludes documents where the specific field is not equal to the value passed. If you think about it, it poses a different meaning from what we want to achieve, but it can be used as long as you understand this and think for yourself whether it is ok for your use case or not. From the docs:

Not-equal (!=) and not-in queries exclude documents where the given field does not exist.

Leave a Reply

Your email address will not be published.