Rodrigo Otani
Rodrigo Otani

Reputation: 165

Spring Data MongoDB BigDecimal support

guys I have a doubt related to BigDecimal value support by Spring Data MongoDB, could someone help me with some news about it, if there will be support for this type, or if anyone knows a workaround to supply my needs. That's the deal: I'm working on a project where we use MongoDB as a DB and Spring as framework, we would like to save the fields where we are supposed to get money values in the database as BigDecimal, I've read that mongo only accepts double as a float number, but I don't think this type is going to be useful. Could you guys give me some light about it?

Upvotes: 16

Views: 27350

Answers (4)

Christoph Strobl
Christoph Strobl

Reputation: 6736

Spring Data MongoDB converts BigDecimal values to String on write and back to when reading. Please have a look at the data mapping and type conversion section of the reference manual.

The default conversion can be modified via @Field(targetType=...) as shown below.

@Field(targetType = DECIMAL128)
private BigDecimal value;

Upvotes: 30

p3quod
p3quod

Reputation: 1679

As is documented at the Spring Data MongoDB - Reference Documentation 18.6. Custom Conversions - Overriding Default Mapping:

The most trivial way of influencing the mapping result is by specifying the desired native MongoDB target type via the @Field annotation. This allows to work with non MongoDB types like BigDecimal in the domain model while persisting values in native org.bson.types.Decimal128 format.

public class Payment {

  @Field(targetType = FieldType.DECIMAL128) 
  BigDecimal value;

}

The desired target type is explicitly defined as Decimal128 which translates to NumberDecimal. Otherwise the BigDecimal value would have been turned into a String:

{
  "value" : NumberDecimal(2.099)
}

Upvotes: 4

Mate Szilard
Mate Szilard

Reputation: 108

I had a corner case where I had a lot of decimals and Decimal128`s constructor raised the following exception:

Failed to convert from type [java.math.BigDecimal] to type [org.bson.types.Decimal128] for value '21.6000000000000000888178419700125232338905334472656250'; nested exception is java.lang.NumberFormatException: Conversion to Decimal128 would require inexact rounding of 21.6000000000000000888178419700125232338905334472656250

The Solution to this was to round down the input:

new Decimal128(source.round(MathContext.DECIMAL128))

Upvotes: 2

Lukasz Frankowski
Lukasz Frankowski

Reputation: 3175

You can change the converter of BigDecimal do Decimal128 which is the java representation of NumberDecimal since mongo 3.4:

@Bean
public MongoCustomConversions mongoCustomConversions() {
    return new MongoCustomConversions(Arrays.asList(

        new Converter<BigDecimal, Decimal128>() {

            @Override
            public Decimal128 convert(@NonNull BigDecimal source) {
                return new Decimal128(source);
            }
        },

        new Converter<Decimal128, BigDecimal>() {

            @Override
            public BigDecimal convert(@NonNull Decimal128 source) {
                return source.bigDecimalValue();
            }

        }


    ));

}

Actually since Spring Data 2.0.7.RELEASE the above changes to following:

@Bean
public MongoCustomConversions mongoCustomConversions() {
    return new MongoCustomConversions(Arrays.asList(
        new BigDecimalDecimal128Converter(),
        new Decimal128BigDecimalConverter()
    ));

}

@WritingConverter
private static class BigDecimalDecimal128Converter implements Converter<BigDecimal, Decimal128> {

    @Override
    public Decimal128 convert(@NonNull BigDecimal source) {
        return new Decimal128(source);
    }
}

@ReadingConverter
private static class Decimal128BigDecimalConverter implements Converter<Decimal128, BigDecimal> {

    @Override
    public BigDecimal convert(@NonNull Decimal128 source) {
        return source.bigDecimalValue();
    }

}

Upvotes: 19

Related Questions