William
William

Reputation: 55

QueryDSL NumberPath<BigDecimal> Greater Than giving inaccurate results from MongoDB Collection

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

Answers (1)

William
William

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

Related Questions