spring-data-mongodb
spring-data-mongodb copied to clipboard
Update with $unset fails with mapping exception
I'm using spring-data-mongodb 4.0.8. On creating an update with an $unset, the following is added to the document:
{ $unset: { fieldName: 1 } }
The value here - 1 - is then attempted to be mapped to the correct type for that field. In my case, that's Decimal128. I get this stack trace:
org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.Integer] to type [org.bson.types.Decimal128] for value [1]
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:47)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:192)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175)
at org.springframework.data.mongodb.core.convert.QueryMapper.applyFieldTargetTypeHintToValue(QueryMapper.java:848)
at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedValue(QueryMapper.java:436)
at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObjectForField(QueryMapper.java:339)
at org.springframework.data.mongodb.core.convert.UpdateMapper.getMappedObjectForField(UpdateMapper.java:160)
at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObject(QueryMapper.java:166)
at org.springframework.data.mongodb.core.convert.UpdateMapper.getMappedObject(UpdateMapper.java:66)
at org.springframework.data.mongodb.core.convert.QueryMapper.convertSimpleOrDocument(QueryMapper.java:578)
at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedKeyword(QueryMapper.java:399)
at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObject(QueryMapper.java:146)
at org.springframework.data.mongodb.core.convert.UpdateMapper.getMappedObject(UpdateMapper.java:66)
at org.springframework.data.mongodb.core.QueryOperations$UpdateContext.getMappedUpdate(QueryOperations.java:864)
at org.springframework.data.mongodb.core.MongoTemplate.doUpdate(MongoTemplate.java:1617)
at org.springframework.data.mongodb.core.MongoTemplate.updateFirst(MongoTemplate.java:1540)
The value here does not relate to the field value, it should not be mapped. My current workaround is to override unset as below:
var update = new Update() {
@Override
public Update unset(String key) {
addMultiFieldOperation("$unset", key, "");
return this;
}
};
The mapping does not fail with an empty string, and an empty string is what's used in the examples in the docs.
@csmager thanks for reporting! We'll see what we can do about this.
@csmager I might be missing something as I was not able to reproduce the issue on 4.0.x nor current main. Could you please take the time to provide a complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem.
Of course - I'd been a little lazy and hoped it'd be easily reproducible. I'll try and reproduce.
The repo is here: https://github.com/csmager/spring-data-mongodb-repro
But I suspect all you need is this. It appears the field mapping to Decimal128 is important - I tried the default (which I think is string), and I tried other types that I thought ought to fail (like ObjectId or Date), and none throw.
@SpringBootTest
class SpringDataMongoDbReproTest {
@Autowired
private MongoTemplate mongoTemplate;
@Test
void throws_on_unset() {
this.mongoTemplate.updateMulti(
new Query(),
new Update()
.unset("field"),
Entity.class
);
}
public static class Entity {
private ObjectId id;
@Field(targetType = FieldType.DECIMAL128)
private BigDecimal field;
}
}
ah thanks - I was using Decimal128 as field type directly.
Yeah, it does seem it's the type hint / mapping that's causing it, it's probably quite a niche issue.
Unfortunately there's no easy fix for the issue as we'd need to provide more context to the update mapping (which needs a bit more thought) to decide if conversion needs to be applied.