DEV Community

Kamil
Kamil

Posted on • Originally published at banach.net.pl on

MongoDB sequences (auto-increment) - The Java Way

tl;dr: Full code available at my Github - elwin013/mongodb-sequences.

One of the missing elements while using MongoDB is lack of the auto-increment fields, commonly called sequences (e.g. in PostgreSQL). For MongoDB Atlas (managed MongoDB solution) there is a posibility to mimic this feature using database triggers (as mentioned on MongoDB page).

But what about self-hosted database? Unfortunately, there are no triggers there (or I’m not aware of them :-)), so we need to improvise and make that happen with custom code.

To make this work we will create a collection called sequence which will have documents with two fields describing the sequence:

  • _id with a name,
  • value with a value.

The code will be relying on MongoDB’s document write atomicity. Linked documentation says:

A findAndModify operation on a document is atomic

In the case of the Java Mongo driver, our operation is findOneAndUpdate. We will be searching for exactly one document with the selected id (name of the sequence), increment value and return that document after the update. Let’s do it!

Below is Sequence record (it can be replaced with the classic POJO if we need to run code on e.g. Java 11 or 8).

import org.bson.codecs.pojo.annotations.BsonId;

public record Sequence(@BsonId String name, Long value) {}
Enter fullscreen mode Exit fullscreen mode

Worth mentioning is the @BsonId annotation - this annotation will make field name an id field (_id) for document in collection. So our document will have two fields - _id (which will contain sequence name and will be mapped to name field in code) and value with value.

Now we can write code to update (increment) and return sequence value. We also want to be sure that the document always is created (update and insert, so upsert) and will be returned after creation. To achieve that we will customize options of findOneAndUpdate request:

var options = new FindOneAndUpdateOptions()
                .upsert(true)
                .returnDocument(ReturnDocument.AFTER);
Enter fullscreen mode Exit fullscreen mode

And the cherry on the top - findOneAndUpdate operation:

 var seq = db.getCollection("sequence", Sequence.class)
            .findOneAndUpdate(
                    Filters.eq("important_sequence"),
                    Updates.inc("value", 1),
                    options
            );
Enter fullscreen mode Exit fullscreen mode

The code above will search for a document with id important_sequence, increment the document’s value field by one and return the document - exactly what we need. And if the document doesn’t exist - it will be created and seq.value() will give us 1.

We can always change the value of sequence using similar code (Updates.set instead of Updates.inc) - but we need to set it to 0 if the next value needs to be 1.

And that is all - we have sequences in MongoDB without any additional tools! Feels great! :-)

Full code available at my Github - elwin013/mongodb-sequences - including record class, DAO and some fancy tests using TestContainers to test code using MongoDB on Docker.

Top comments (0)