spring-projects / spring-projects/spring-data-mongodb
"update one" aggregation update with optimistic locking throws exception
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 1.7k
- Forks
- 1.1k
- PR merge metrics
- No merged PRs in 30d
Description
Hi,
I was wondering if I used the aggregation update badly.
I'm currently using spring-data-mongodb 3.3.4.
In fact, update first throws an exception while update all doesn't because of the optimistic lock checking in the method doUpdate of ReactiveMongoTemplate.
In order to reproduce the exception, we need to do an aggregation update and specify a matching query that doesn't match any document. I currently have two stages in my aggregation pipeline.
The exception occurs while trying to get MappedUpdate from the entity before checking if it contains the version property in order to throw an OptimisticLockingFailureException. A "'name' must not be null" is thrown.
Above this method we can see that we make a difference between aggregation update and basic update. My suggestion would be to change the code as follows but didn't check it yet :
Change from :
if (entity != null && entity.hasVersionProperty() && !multi) {
if (updateResult.wasAcknowledged() && updateResult.getMatchedCount() == 0) {
Document updateObj = updateContext.getMappedUpdate(entity);
if (containsVersionProperty(queryObj, entity))
throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity: "
+ updateObj.toString() + " to collection " + collectionName);
}
}
to:
if (entity != null && entity.hasVersionProperty() && !multi) {
if (updateResult.wasAcknowledged() && updateResult.getMatchedCount() == 0) {
if (containsVersionProperty(queryObj, entity)){
List<Document> updateObjs = updateContext.isAggregationUpdate() ? updateContext.getUpdatePipeline(entityClass): List.of(updateContext.getMappedUpdate(entity));
String updateObjStr = updateObjs.stream().map(String::valueOf).collect(Collectors.joining("[", ",\n", "]"));
throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity: "
+ updateObjStr + " to collection " + collectionName);
}
}
}
Moving the build of updateObj to the if block avoid building it when we know that query object doesn't contain the version property save some computation.
We may, as well, move it to the previous if condition if getting version property don't do any computation as follow :
if (!multi && containsVersionProperty(queryObj, entity)) {
if (updateResult.wasAcknowledged() && updateResult.getMatchedCount() == 0) {
List<Document> updateObjs = updateContext.isAggregationUpdate() ? updateContext.getUpdatePipeline(entityClass): List.of(updateContext.getMappedUpdate(entity));
String updateObjStr = updateObjs.stream().map(String::valueOf).collect(Collectors.joining("[", ",\n", "]"));
throw new OptimisticLockingFailureException("Optimistic lock exception on saving entity: "
+ updateObjStr + " to collection " + collectionName);
}
}
As a workaround, since the match query target a document id, I used all instead of first and all works as expected since I don't use the optimistic locking in my case.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in ReactiveMongoTemplate.doUpdate, focusing on the optimistic-locking branch after an acknowledged update matches no documents. Reproduce an aggregation update with an unmatched query and compare update-one with update-all behavior. Done means update-one no longer throws the "'name' must not be null" error while the intended optimistic-locking exception remains available when appropriate.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, mongodb, spring
- Domain
- backend, database
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100