MongoDB sequences (auto-increment) - The Java Way
Tags: mongodb, java, database
Published: 2022-12-02 21:39:09

---
title: MongoDB sequences (auto-increment) - The Java Way
published: true
date: 2022-12-02 21:30:00 UTC
tags: mongodb, java, database
canonical_url: https://banach.net.pl/posts/2022/mongodb-sequences-autoincrement-the-java-way/
---

> tl;dr: Full code available at my Github - [elwin013/mongodb-sequences](https://github.com/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](https://www.mongodb.com/basics/mongodb-auto-increment)).

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](https://www.mongodb.com/docs/manual/core/write-operations-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).

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

public record Sequence(@BsonId String name, Long value) {}
```

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:

```java
var options = new FindOneAndUpdateOptions()
                .upsert(true)
                .returnDocument(ReturnDocument.AFTER);
```

And the cherry on the top - `findOneAndUpdate` operation:

```java
 var seq = db.getCollection("sequence", Sequence.class)
            .findOneAndUpdate(
                    Filters.eq("important_sequence"),
                    Updates.inc("value", 1),
                    options
            );
```

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](https://github.com/elwin013/mongodb-sequences) - including record class, DAO and some fancy tests using [TestContainers](https://www.testcontainers.org/) to test code using MongoDB on Docker.