Reputation: 294
I have a collection with the following data:
id: 1, item: book, version: 1
id: 2, item: book, version: 2
id: 3, item: cat, version: 1
id: 4, item: cat, version: 2
id: 5, item: cat, version: 3
I would like to insert a new element by just mentioning the item itself. The id is of course auto-generated. The version should be automatically incremented based on the item field. This means that if I would like to insert a new document with "book" item it should look like:
id: 6, item: book, version: 3
How it's possible by using in Spring Boot in a MongoDB database.
Situation: Actually I have two collections: changes, states. In a server side application we have businesses. We have a state document in the states collection for every business. There can be data changes in a business, when a change happens we get the state of the business from the state collection. It contains a businessID and a version. The version is the overall data version of the business. We increment the version number with one and save it to the states document. Then we save a document in the changes collection which contains a businessId a the new version and data regarding the actual change. The problem is that this is two operation in the database. If a lot of changes are happening with the business then the data in this two collections can be corrupted. The plan is to remove the states collection and keeep just the changes collection. Then we have to do the following with one singe databes operation: find the biggest version of one business in the changes collection, then insert a new document there with an incremented version number and the new change. I dont know how i could make a find and an insert operations onces
Upvotes: 0
Views: 1504
Reputation: 1496
You can use another collection for saving the id sequence. Every time that someone requests a new id, the method ensures that it's increment the id.
@Document
public class CollectionSeq {
@Id
@Indexed( unique = true)
private String collection;
private long current = 1;
}
You can get the next id:
public long next(String collection) {
CollectionSeq next = operations.findAndModify(
query(where("collection").is(collection)),
new Update().inc("current", 1),
options().returnNew(true).upsert(true),
CollectionSeq.class
);
return Objects.requireNonNull(next).getCurrent();
}
And before to save a new document of the collection assign the id.
Item item = new Item();
item.setId(collectionSeqRepository.next("item"));
item.setVersion(4);
...
itemRepository.save(item)
The sequencer collection looks like this:
collection: item, current: 3
collection: book, current: 100
collection: version, current: 4
According to official docs, MongoDB does provide an isolated update and return.
Here is the MongoDB official doc link: Why findAndModify is Atomic.
Concurrency control allows multiple applications to run concurrently without causing data inconsistency or conflicts.
One approach is to create a unique index on a field that can only have unique values. This prevents insertions or updates from creating duplicate data. Create a unique index on multiple fields to force uniqueness on that combination of field values. For examples of use cases, see update() and Unique Index and findAndModify() and Unique Index.
Another approach is to specify the expected current value of a field in the query predicate for the write operations.
Upvotes: 1