Recently I found that MongoDB does not support java's java.math.BigDecimal as you can read in the official spring data mongodb documentation
As it turns out java.math.BigDecimal will be converted to java.lang.String when saved to the database and parsed back to BigDecimal which in most cases I guess it's alright
However as I found out things get broken when trying to perform range queries on this field such as : $gte, $lte you will get inconsistent results since MongoDB sees this as a String
Luckily this can be easily fixed by creating 2 custom converters (one for each side), below is how I've done it :
1. Define custom converters by implementing the appropriate interface
import org.springframework.core.convert.converter.Converter; import java.math.BigDecimal; public class BigDecimalToDoubleConverter implements Converter<BigDecimal, Double> { @Override public Double convert(BigDecimal source) { return source.doubleValue(); } }
import org.springframework.core.convert.converter.Converter; import java.math.BigDecimal; public class DoubleToBigDecimalConverter implements Converter<Double, BigDecimal> { @Override public BigDecimal convert(Double source) { return new BigDecimal(source); } }
2. Configure the MongoTemplate to use the custom converters
@Configuration public class MongoDBConfig { //MongoDB properties read from the application.yaml configuration file (to handle different profiles) @Value("${spring.data.mongodb.host}") private String mongoHost; @Value("${spring.data.mongodb.port}") private int mongoPort; @Value("${spring.data.mongodb.database}") private String mongoDatabase; @Bean public MongoTemplate mongoTemplate() throws Exception { MongoTemplate mongoTemplate = new MongoTemplate(mongo(), mongoDatabase); MappingMongoConverter mongoMapping = (MappingMongoConverter) mongoTemplate.getConverter(); mongoMapping.setCustomConversions(customConversions()); // tell mongodb to use the custom converters mongoMapping.afterPropertiesSet(); return mongoTemplate; } /** * Configure the MongoDB client * **/ @Bean public Mongo mongo() throws Exception { return new MongoClient(mongoHost, mongoPort); } /** * Returns the list of custom converters that will be used by the MongoDB template * **/ public CustomConversions customConversions() { return new CustomConversions(Arrays.asList(new DoubleToBigDecimalConverter(), new BigDecimalToDoubleConverter())); } }
In the newer Spring Data they added simpler way to support BigDecimal:
ReplyDelete@Field(targetType = FieldType.DECIMAL128)
BigDecimal value;
https://docs.spring.io/spring-data/data-mongodb/docs/current/reference/html/#mongo.custom-converters
Any suggestion for same issue in MySQL?
ReplyDelete