返回 登录
0

谈MongoDB Shell下的长整型截断问题

原文:Long Numbers Are Truncated in MongoDB Shell
作者: Gian Maria Ricci
译者: 孙思
责编:孙思,关注数据库领域,寻求报道或者投稿请发邮件sunsi@csdn.net,另有「CSDN 高级数据库技术群」,内有诸多知名互联网公司的大牛,欢迎加微信sunlovesi申请入群,备注姓名+公司+职位。

MongoDB Shell下的长整型问题是MongoDB臭名昭著的缺点。在这短暂的阅读中,Gian Maria Ricci(Linkedin)将解释他是如何解决这一问题的。

在Mongo shell中简单的代码:

db.TestCollection.insert({"_id" : 1, "Value" : NumberLong(636002954392732556) })
db.TestCollection.find()

你想要在Mongo中插入一条记录,然后返回记录。记录被插入后返回值会令人大吃一惊。下面是从RoboMongo得到的输出:

{
 "_id" : 1.0,
 "Value" : NumberLong(636002954392732544)
}

属性“值”中没有你插入的数字,这似乎是舍入和一些精度的丢失,即使它是一个NumberLong型和一个完全有效的64位长整型636002954392732556。这种行为让我很吃惊,因为我希望舍入的只有double型,而不是一个Int64的长整型。

实际上,使用64位的双精度浮点数表示,不能拥有一个64位长整型相同的精度,因为64位的一部分用来存储一个指数。如果你试图用双精度浮点来表示一个像636002954392732556一大串数字,那么一些四舍五入将会发生。如果你不相信,试试这个在线转换器转换636002954392732556,这里是结果:

图片描述

图1:浮点数舍入

上面就是舍入带来的问题,因为有些数字转换为浮点数格式,即使我使用NumberLong bson扩展指定,我想要一个长整型而不是一个浮点类型。

这背后的原因很微妙,接着试另一个例子,在Mongo shell(RoboMongo环境)中只输入NumberLong型(636002954392732556),并验证结果。

图片描述

图2:NumberLong直接从shell中获取舍入

这揭示了一个错误,在数返回时,则用引号括起来了,这说明引用是有问题的。在JavaScript中,每一个数字都是double型,如果你写NumberLong型(636002954392732556)JavaScript 转化这个作为参数传递的数字 636002954392732556来调用NumberLong函数。由于在JavaScript中的每个数字是一个double型,636002954392732556这个数会舍入之前它传递给NumberLong函数。

如果你周围有引用的数字,在这种情况下,将一个字符串传递给NumberLong型,舍入并不会发生,以及NumberLong函数是完全有能力将字符串转换为一个数字。

在Mongo shell中,当你使用NumberLong型创建数字总是使用引号,实际上,这个错误只发生在非常大的数字中,但是你需要明白如果创建一个脚本,那么就需要使用NumberLong型。

评论