首页 文章

使用MongoDB中的Spring Data MongoDB对存储为BigDecimal类型的数值进行排序

提问于
浏览
2

我正在使用教程(https://spring.io/guides/tutorials/data/2/)学习Spring Data MongoDB . 在本教程中,成本类型为BigDecimal,如下所示,它在MongoDB中存储为"string" . 所以,当我试图通过成本字段按升序排序得到排序结果时,我得到了错误的结果 .

我发现使用BigDecimal类是计算的最佳方法 . 但是,如果我使用MongoDB中的Spring Data MongoDB将数字保存为BigDecimal类型,它将保存为字符串类型,我会得到一个错误的排序结果,如本教程 .

为了精确起见,我能做些什么来获得正确的数字排序结果?你能帮我解决这个问题吗?非常感谢你提前 .

例如,

1> MenuItem类

@Document(collection = "menu")
public class MenuItem {
  @Id
  private String id;

  @Field("itemName")
  @Indexed
  private String name;
  private BigDecimal cost;

2>创建MenuItem的实例

MenuItem item = new MenuItem();
item.setDescription("Peanutty Noodles, perfect for every occasion.");
item.setName("Yummy Noodles");
item.setCost(new BigDecimal("52.99"));


MenuItem item = new MenuItem();
item.setDescription("Rice, Egg Fried");
item.setName("Yummy Rice");
item.setCost(new BigDecimal("211.99"));

3>排序结果

db.menu.find() . sort({cost:1})

{“_ id”:ObjectId(“53e982f0300475a4fbab8c32”),“_ class”:“com.yummynoodlebar.persistence.domain.MenuItem”,“itemName”:“Yummy Rice”,“description”:“Rice,Egg Fried”,“ingredients” “:[{”name“:”Egg“,”description“:”Chicken Eggs“},{”name“:”Rice“,”description“:”Straight White Rice“}],”cost“:”211.99“ ,“minutesToPrepare”:0}

{“_ id”:ObjectId(“53e982f0300475a4fbab8c33”),“_ class”:“com.yummynoodlebar.persistence.domain.MenuItem”,“itemName”:“Yummy Rice”,“description”:“Rice,Egg Fried”,“ingredients” “:[{”name“:”Egg“,”description“:”Chicken Eggs“},{”name“:”Rice“,”description“:”Straight White Rice“}],”cost“:”211.99“ ,“minutesToPrepare”:0}

{“_ id”:ObjectId(“53e982f0300475a4fbab8c2f”),“_ class”:“com.yummynoodlebar.persistence.domain.MenuItem”,“itemName”:“Yummy Noodles”,“description”:“Peanutty Noodles,适合各种场合 . “,”成分“:[{”name“:”Peanuts“,”description“:”A Nut“},{”name“:”Egg“,”description“:”用于面条“},{”name “:”面条“,”描述“:”脆,可爱的面条“}],”成本“:”52.99“,”minutesToPrepare“:0}

{“_ id”:ObjectId(“53e982f0300475a4fbab8c30”),“_ class”:“com.yummynoodlebar.persistence.domain.MenuItem”,“itemName”:“Yummy Noodles”,“description”:“Peanutty Noodles,适合各种场合 . “,”成分“:[{”name“:”Peanuts“,”description“:”A Nut“},{”name“:”Egg“,”description“:”用于面条“},{”name “:”面条“,”描述“:”脆,可爱的面条“}],”成本“:”52.99“,”minutesToPrepare“:0}

{“_ id”:ObjectId(“53e982f0300475a4fbab8c31”),“_ class”:“com.yummynoodlebar.persistence.domain.MenuItem”,“itemName”:“Yummy Noodles”,“description”:“Peanutty Noodles,适合各种场合 . “,”成分“:[{”name“:”Egg“,”description“:”用于面条“},{”name“:”Peanuts“,”description“:”A Nut“},{”name “:”面条“,”描述“:”脆,可爱的面条“}],”成本“:”52.99“,”minutesToPrepare“:0}

3 回答

  • 1

    遗憾的是,MongoDB原生的 BigDecimalnot supported . 这就是我们默认将其转换为 String 的原因 .

    对于更多的数字处理,特别是如果您处理价格等,我们通常建议改为存储双打,并将它们直接转换为 BigDecimal s,以便在域对象中进行算术运算 .

  • 1

    如果您正在处理Money - 并且“cost”看起来像那样 - 那么在代码中使用Money类 . 钱将带有金额和货币 . Money有方法可以将数量作为BigDecimal等获取 . 将MongoDB中的钱持久化为这样的丰富形状:

    {cost:{amt:21199,ccode:“USD”}}

    所有相同货币的数字操作(eq,gt,lt等)都能正常工作 . 而且你无论如何都不能在数据库中进行交叉货币比较,因为汇率是动态的 .

    http://www.moschetti.org/rants/mongomoney.html

  • 0

    从版本 3.4 开始,MongoDB通过新的十进制数据类型(decimal128)添加了对"BigDecimal"的支持 . 但是,spring数据默认仍然将Java BigDecimal 映射到MongoDB string (我想这是为了向后兼容) . 好消息是可以通过在spring boot应用程序中注入 CustomConversions 来简单地覆盖默认映射,如下所示:

    @Bean
    CustomConversions customConverions() {
      Converter<Decimal128, BigDecimal> decimal128ToBigDecimal = new Converter<Decimal128, BigDecimal>() {
        @Override
        public BigDecimal convert(Decimal128 s) {
          return s==null ? null : s.bigDecimalValue();
        }
      };
    
      Converter<BigDecimal, Decimal128> bigDecimalToDecimal128 = new Converter<BigDecimal, Decimal128>() {
        @Override
        public Decimal128 convert(BigDecimal s) {
          return s==null ? null : new Decimal128(s);
        }
      };
    
      return new CustomConversions(Arrays.asList(decimal128ToBigDecimal, bigDecimalToDecimal128));
    }
    

    请检查this post for more detailed information and even a complete example .

相关问题