Reputation: 55
While trying to apply a QueryDSL implementation for search filtering, I have encountered the following issue, which is quite confusing to say the least.
Consider the following properties in a MongoDB collection called Payments:
Object 1
- amountDue (Object)
- amount => 106.00 (String)
Object 2
- amountDue (Object)
- amount => 58.80 (String)
These values are generated by the system, and the actual data type of the amountDue
object is an org.joda.BigMoney object.
These properties are applied in a binding method which is used to provide a QueryDSL predicate such that any Payment objects which have an amountDue.amount
property greater than that specified in a search query is returned. Such method is described below:
@Override
public Predicate bind(NumberPath<BigDecimal> bigDecimalNumberPath, Collection<? extends BigDecimal> value) {
ArrayList<? extends BigDecimal> amounts = new ArrayList<>(value);
return bigDecimalNumberPath.gt(amounts.get(0));
}
The following describes the cases which I am testing with, among others, with the respective results:
{URL}/payments/filter?page=0&amountDue.amount=10.00
, which internally is converted to a 'amountDue.amount > 10.00' predicate returns both Objects [Correct]
{URL}/payments/filter?page=0&amountDue.amount=20.00
, which internally is converted to a 'amountDue.amount > 20.00' predicate returns Only Object 2 [Incorrect]
{URL}/payments/filter?page=0&amountDue.amount=60.00
, which internally is converted to a 'amountDue.amount > 60.00' predicate returns no Objects [Incorrect]
{URL}/payments/filter?page=0&amountDue.amount=100.00
, which internally is converted to a 'amountDue.amount > 100.00' predicate returns Only Object 2 [Incorrect]
{URL}/payments/filter?page=0&amountDue.amount=150.00
, which internally is converted to a 'amountDue.amount > 150.00' predicate returns Only Object 2 [Incorrect]
The moment the amount
value of Object 1 is changed to a value less than 100, then all cases return correct results.
What are your suggestions/recommendations please?
Thanks for your time!!
Upvotes: 2
Views: 2060
Reputation: 55
The following has been applied to resolve the issue posted above:
First create a Decimal128 (Bson Type) To Big Decimal class converter:
public class Decimal128ToBigDecimalConverter implements Converter<Decimal128, BigDecimal> {
@Override
public BigDecimal convert(Decimal128 source) {
return source.bigDecimalValue();
}
}
Then create a Big Decimal to Decimal128 (Bson Type) class converter:
public class BigDecimalToDecimal128Converter implements Converter<BigDecimal, Decimal128> {
@Override
public Decimal128 convert(BigDecimal source) {
return new Decimal128(source);
}
}
Finally, configure your MongoConfig file to make use of the converters:
@Bean
public MongoTemplate mongoTemplate() throws Exception {
MongoTemplate mongoTemplate = new MongoTemplate(mongo(), getDatabaseName());
MappingMongoConverter mongoMapping = (MappingMongoConverter) mongoTemplate.getConverter();
mongoMapping.setCustomConversions(customConversions());
mongoMapping.afterPropertiesSet();
return mongoTemplate;
}
public CustomConversions customConversions() {
return new CustomConversions(Arrays.asList(new Decimal128ToBigDecimalConverter(), new BigDecimalToDecimal128Converter()));
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.config.AbstractMongoConfiguration#mongo()
*/
@Bean
@Override
public Mongo mongo() throws Exception
{
return new MongoClient();
}
The solution has been implemented by following the example listed here: http://ufasoli.blogspot.com.mt/2017/06/custom-converter-for-mongodb-and-spring.html
Upvotes: 2