Generating Auto-Incrementing Sequences With Firestore

Anthony Miller
Firebase Developers
3 min readAug 8, 2020

--

After more than a year of reading and playing around on the surface with various aspects of Firebase it was time take the plunge and dive into using Firebase with my next project.

Firebase simplifies many of the initial starting hurdles when commencing a new project such as providing Authentication out of the box, Firestore’s CRUD operations are straight forward with its NoSQL database as a service plus many more features I’m still learning.

How to generate your own sequence value?

I know I’m possibly approaching this with traditional SQL database mindset, but who doesn’t want to be able to generate the next sequence value when creating an order? The random sets of characters of the document ID isn’t a user friendly order identifier when emailing a customer their latest purchase.

Enter FieldValue.increment(), it allows for the incrementing or decrementing values atomically on an individual document with ease, according to the documentation and blog post here.

How to read the incremented value and set this on another document?

I hit a road block with FieldValue.increment(), it simply didn’t solve my use case and reading through the various features of the Firestore database there was no easy way to implement an auto-incrementing sequence value.

This is where Firebases’s Cloud Functions and transaction come to the rescue. I was able to generate an auto-incrementing sequence by storing a counter’s current value in a document and then splitting each counter into their own document, thus reducing locking contention.

Let’s get started

First thing first, with Firebase Cloud Functions we need to initialise the instance of the Firebase Admin SDK globally. Here are some utility functions to ensure the Admin SDK is only initialised once:

Next is implementing the Cloud Function to listen to the creation of the Order documents to trigger the generation of the next order number and then updating the order itself.

Notice the usage of database runTransaction function, this is to ensure that the call to getIncrement locks the counter’s document while the reading the current value and then updating with the incremented value.

Note:- One nuance when working with transactions, Firebase requires all read operations need to happen before any write operations so order of execution is important.

Each named counter will have their own document in a collection reducing contention for an individual counter document, i.e. a counter document for orders and another for invoices.

Firestore Counters Collection

The getIncrement() function could also be used via a Firebase HTTP Cloud function or a Firebase Callable function, if needing the sequence value prior to creating the document into the Firestore database.

Conclusion

Firebase is truly an amazing database as a service allowing the developer to concentrate on delivering value without the need to build out an API layer to get started.

This solution introduces some performance impacts with sustained writes on the counter document itself limited to 1 per second and writes to the consuming collection are limited to 500 per second — see the docs.

Hence, a feature request extension for Firestore would be for FieldValue.increment to take a parameter for a counter name and all this additional plumbing code could be handled by Firebase itself.

--

--