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) {}
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);
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
);
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)