MongoDB - 十进制类型的值怎么样?

时间:2012-07-18 12:57:19

标签: mongodb decimal bigdecimal bson

我目前正在学习并将MongoDB应用于一个小型金融相关项目。


当我阅读MongoDB in Action时,它说:

  

BSON数字类型通常出现的唯一其他问题是   缺乏小数支持。这意味着,如果你正在计划   在MongoDB中存储货币值,您需要使用整数类型   并保持以美分为单位。


我的财务相关产品将涉及一些货币价值,但我有点困惑或担心上述声明。以下是我的问题:

  1. 我可以对项目中的double使用currency values吗?
  2. 如果我直接使用double,会发生什么或后果?
  3. 如果小数类型是金融产品必备的东西,那么使用MongoDB是个坏主意吗?
  4. 这是什么意思you need to use an integer type and keep the values in cents?这是否意味着如果我要存储1.34 dollars,那么我应该存储134 cents
  5. 由于

6 个答案:

答案 0 :(得分:32)

如果您想要出于财务目的的精确表示,则双精度或浮点值不适合,因为小数部分会受到舍入误差的影响。某些十进制值不能使用基于二进制的浮点表示,必须近似。

对于技术性较差的介绍,请参阅The trouble with rounding floating point numbers;如果您想要擅长,请阅读What Every Computer Scientist Should Know About Floating-Point Arithmetic

使用整数类型(以美分存储值)的建议是为了避免潜在的舍入错误。这种方法在Using a Scale Factor的MongoDB文档中被描述为“modelling monetary data”,是MongoDB 3.2及更早版本的一般解决方法。

MongoDB 3.4包含一个新的Decimal BSON type,它为操作货币数据字段提供了精确的精确度。

答案 1 :(得分:4)

如果您不想将货币存储为分数值,则可以将1.34美元的货币存储为如下对象:

{
    major: 1,
    minor: 34,
    currency: "USD"
}

使用这样的对象进行任何数学运算都不容易,也不会使用商业舍入规则。但是你不应该在数据库上做任何业务逻辑,特别是当它是像MongoDB这样的“哑”数据库时。

您应该做的是从/向应用程序中的Money类序列化/反序列化这些对象,这些类实现了关于舍入规则的基本货币数学运算,并在您尝试执行操作时抛出异常不同的货币单位($12.34 + 14.95€ = error - 必须首先通过提供汇率将一种货币转换为另一种货币。)

答案 2 :(得分:4)

如果您正在使用Mongoose,那么您可以在架构定义中使用getter / setter函数,例如。

function getDecimalNumber(val) {    return (val/1000000); }
function setDecimalNumber(val) {    return (val*1000000); }

适用于

等架构对象
balance: { type: Number, default: 0, get: getDecimalNumber, set: setDecimalNumber },

要乘/除的零数取决于您想要的精度。

答案 3 :(得分:4)

看起来MongoDB最终添加了对小数的支持,虽然在撰写本文时这只是完成开发,但希望它很快就可以在稳定版本(3.4?)中使用。

https://jira.mongodb.org/browse/SERVER-1393

答案 4 :(得分:3)

我知道这篇文章很老但是它在Google上排名很高......所以...

存储财务数据的最佳解决方案是使用MongoDB自己在http://docs.mongodb.org/v2.6/tutorial/model-monetary-data/#monetary-value-exact-precision记录的精确精度。

{price: 9990, currency: "USD" }

当您需要数据时除以100,假设您需要2位精度。缺点是你总是需要以相同的精度工作。

答案 5 :(得分:2)

MongoDb添加了对Decimal data type in 3.4 version的支持。它也可以从shell获得。

  

3.4增加了对decimal128格式的支持,使用新的十进制数据类型。 decimal128格式支持最多34位小数的数字   数字(即有效数字)和指数范围-6143到   6144。

     

与双数据类型不同,后者仅存储近似值   十进制值,十进制数据类型存储确切的值。对于   例如,十进制NumberDecimal(" 9.99")的精确值为9.99   其中,双9.99的近似值为   9.9900000000000002131628 ...