参考 > 资料模型 > 数据模型示例和模式 > 模型特定的应用程序上下文 > 模型货币数据
处理货币数据的应用程序通常需要能够捕获货币的分数单位,并且在执行算术运算时需要精确精确地模拟小数舍入。许多现代系统使用的基于二进制的浮点算法(即float,double)无法表示精确的十进制小数,并且需要某种程度的近似值,使其不适用于货币算法。在对货币数据进行建模时,此约束是重要的考虑因素。
在MongoDB中,有几种使用数字模型和非数字模型对货币数据进行建模的方法。
如果你需要在数据库中查询准确,数学上有效的匹配或需要进行服务器端的运算,例如,数字模型可能是合适的$inc
,$mul
和
聚合框架算术。
以下方法遵循数值模型:
long
乘以10的幂后可以将货币值转换为64位整数(BSON类型)。如果不需要对货币数据执行服务器端算术,或者如果服务器端近似值足够,则使用非数字模型对货币数据进行建模可能是合适的。
以下方法遵循非数值模型:
string
,另一个字段存储值的基于二进制的浮点(double
BSON类型)近似值。3.4版的新功能。
所述decimal
BSON类型使用IEEE 754 DECIMAL128基于十进制浮点编号格式。与基于二进制的浮点格式(即double
BSON类型)不同,decimal128不能近似十进制值,并且能够提供处理货币数据所需的精确精度。
使用构造函数从mongo
外壳decimal
中分配和查询值NumberDecimal()
。以下示例将包含汽油价格的文档添加到gasprices
集合中:
以下查询与上面的文档匹配:
有关decimal
类型的更多信息,请参见
NumberDecimal。
可以decimal
通过执行一次转换或通过修改应用程序逻辑以在访问记录时执行转换来将集合的值转换为类型。
小费
从4.0版开始,可以替代下面概述的过程,可以使用$convert
和其辅助
$toDecimal
运算符将值转换为NumberDecimal()
。
通过遍历集合中的所有文档,将货币值转换为decimal
类型,然后将文档写回到集合中,可以转换集合。
注意
强烈建议将decimal
值作为新字段添加到文档中,并在新字段的值经过验证后再删除旧字段。
警告
确保decimal
在隔离的测试环境中测试转换。使用MongoDB 3.4版创建或修改数据文件后,它们将不再与以前的版本兼容,并且不支持降级包含小数位的数据文件。
比例因子转换:
考虑以下使用比例因子方法并将货币值保存为代表美分数的64位整数的集合 :
的long
值可以被转换为适当格式化的
decimal
相乘值price
,并
NumberDecimal("0.01")
使用所述$multiply
操作者。以下聚合管道priceDec
在$addFields
阶段中将转换后的值分配给新字段:
可以使用以下db.clothes.find()
查询来验证聚合管道的结果
:
如果您不想使用该decimal
值添加新字段,则可以覆盖原始字段。以下
update()
方法首先检查price
存在的并且是long
,然后将long
值转换为
decimal
并将其存储在price
字段中:
可以使用db.clothes.find()
查询验证结果:
非数值转换:
考虑以下使用非数字
模型的集合,该货币集合
将货币值另存为,并string
带有该值的精确表示形式:
以下函数首先检查是否price
存在,并将其string
转换string
为一个decimal
值并将其存储在priceDec
字段中:
该函数不向命令行输出任何内容。可以使用db.clothes.find()
查询验证结果:
可以decimal
从应用程序逻辑中执行到类型的转换。在这种情况下,应用程序修改为在访问记录时执行转换。
典型的应用程序逻辑如下:
decimal
类型是否正确decimal
字段不存在:使用比例因子方法对货币数据进行建模:
USD
。例如,以下将以1000 缩放以保持高达十分之一分的精度。9.99 USD
该模型假定对于给定的货币值:
使用此模型时,应用程序必须在执行值的适当缩放时保持一致。
有关此模型的用例,请参见数值模型。