Greetings!
If you have used RDBMS like MySQL or Oracle you know that those databases support auto-increment fields or sequences. However MongoDB's way of ID is using an ObjectId which is a large string. However if you want an unique sequence what will you do?
One solution is of cause to use RDBMS solution like Oracle. Unlike NoSQL solutions, RDBMS have problems with scaling. Let's imagine that to overcome scaling problems we are using MongoDB.
Eventhough MongoDB doesn't offer this feature out of box, we can implement it using it's atomic operations.
The trick is to create a collection with desired name as the _id and findAndModify with $inc.
However, I could run 15,000 counts per second on average in my Intel 1.80GHz 4 core 8 threads CPU, 8GB RAM, Ubuntu 18 Dell Laptop.
First, we can create our Collection like this.
Happy coding.
If you have used RDBMS like MySQL or Oracle you know that those databases support auto-increment fields or sequences. However MongoDB's way of ID is using an ObjectId which is a large string. However if you want an unique sequence what will you do?
One solution is of cause to use RDBMS solution like Oracle. Unlike NoSQL solutions, RDBMS have problems with scaling. Let's imagine that to overcome scaling problems we are using MongoDB.
Why do we need a unique sequence?
We will need unique sequences for several reasons.- Design a hit counter.
- Short string generation (https://www.slmanju.com/2021/07/basebase62-encoding-with-java.html).
- Rate limiting.
- Easy to read identifier value.
- You are migrating from relational database.
Eventhough MongoDB doesn't offer this feature out of box, we can implement it using it's atomic operations.
The trick is to create a collection with desired name as the _id and findAndModify with $inc.
db.counters.insert({
_id: "my-sequence",
sequence: 0
}
db.counters.findAndModify({
query: { _id: "my-sequence" },
update: { $inc: { sequence: 1 } },
new: true
})
Downside
As this is atomic operation we can serve only 1 thread at a time. Hence we have to carefull with the performance panelty. Also, this would be a single point of failure.However, I could run 15,000 counts per second on average in my Intel 1.80GHz 4 core 8 threads CPU, 8GB RAM, Ubuntu 18 Dell Laptop.
Implement with Spring MongoDB
Now we can use this trick in our applications easily. As the Spring framework provides the MongoDB integration, all we need to do is call the appropriate methods.First, we can create our Collection like this.
@Document(collection = "counters")
@Getter @Setter
public class Counter {
@Id
private String id;
private long sequence;
}
Then use Spring MongoDB methods
to findAndModifiy the sequence.
@Component
public class SequenceGenerator {
@Autowired
private MongoTemplate mongoTemplate;
public long findNext() {
Query query = query(where("_id").is("url_shortner"));
Update update = new Update().inc("sequence", 1);
Counter counter = mongoTemplate.findAndModify(query, update, options().returnNew(true), Counter.class);
return counter.getSequence();
}
}
long sequence = sequenceGenerator.findNext();
It
is extremely fun learning experience anyway :)Happy coding.
https://github.com/slmanju/codekata/tree/master/globalcounter
https://www.mongodb.com/blog/post/generating-globally-unique-identifiers-for-use-with-mongodb
https://docs.mongodb.com/manual/reference/operator/update/inc/
https://docs.mongodb.com/manual/reference/command/findAndModify/
References
https://www.mongodb.com/basics/mongodb-auto-incrementhttps://www.mongodb.com/blog/post/generating-globally-unique-identifiers-for-use-with-mongodb
https://docs.mongodb.com/manual/reference/operator/update/inc/
https://docs.mongodb.com/manual/reference/command/findAndModify/
Comments
Post a Comment