我目前正在学习并将MongoDB应用于一个小型金融相关项目。
当我阅读MongoDB in Action时,它说:
BSON数字类型通常出现的唯一其他问题是 缺乏小数支持。这意味着,如果你正在计划 在MongoDB中存储货币值,您需要使用整数类型 并保持以美分为单位。
我的财务相关产品将涉及一些货币价值,但我有点困惑或担心上述声明。以下是我的问题:
double
使用currency values
吗?double
,会发生什么或后果?you need to use an integer type and keep the values in cents
?这是否意味着如果我要存储1.34 dollars
,那么我应该存储134 cents
? 由于
答案 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?)中使用。
答案 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 ...