0

我想在 mongdb 中存储一些非常大的整数,确切地说(几千个十进制数字)。这当然不适用于 BSON 支持的标准类型,考虑到我想执行范围搜索和类似的事情,我正在尝试考虑最优雅的解决方法。此要求不包括将整数存储为字符串,因为它使范围搜索不切实际。

我能想到的一种方法是使用标准整数的(可变长度)数组对 2^32 扩展进行编码,并向该数组添加数组本身长度的第一个条目。这样,这些数组的字典顺序对应于任意大整数的通常顺序。

例如,在一个集合中,我可以有 5 个文档

{"name": "me", "fortune": [1,1000]}
{"name": "scrooge mcduck", "fortune": [11,1,0,0,0,0,0,0,0,0,0,0]}
{"name": "bruce wayne","fortune": [2, 10,0]}
{"name": "bill gates", "fortune": [2,1,1000]}
{"name": "francis", "fortune": [0]}

因此布鲁斯韦恩的净资产是 10*2^32,比尔盖茨的 2^32+1000 和斯克罗吉麦克杜克的 2^320。

然后我可以使用 {"fortune":1} 进行排序,并在我的机器上(使用 pymongo)按 francis < me < bill < bruce < scrooge 的顺序返回它们,正如预期的那样。

但是,我假设我没有在任何地方看到关于 BSON 数组比较方式的记录,并且范围搜索似乎不像我想的那样工作(例如,

find({"fortune":{$gte:[2,5,0]}}) 

不返回任何文件,但我希望得到 bruce 和 scrooge)。

谁能帮我?谢谢

4

2 回答 2

0

您可以改为存储左填充字符串,这些字符串表示等于财富的精确整数。

eg.  "1000000" = 1 million
     "0010000" = 10 thousand
     "2000000" = 2 million
     "0200000" = 2 hundred thousand 

左填充零将确保这些字符串的字典比较直接对应于它们作为数值的比较。您必须在这里假设一个安全的 MAXIMUM 可能的财富值,比如一个 20 位数字,并相应地填充 0 所以示例文档将是:

  {"name": "scrooge mcduck", "fortune": "00001100000000000000" }
  {"name": "bruce wayne",    "fortune": "00000200000000000000" }

查询:

> db.test123.find()
{ "_id" : ObjectId("4f87e142f1573cffecd0f65e"), "name" : "bruce wayne", "fortune" : "00000200000000000000" }
{ "_id" : ObjectId("4f87e150f1573cffecd0f65f"), "name" : "donald", "fortune" : "00000150000000000000" }
{ "_id" : ObjectId("4f87e160f1573cffecd0f660"), "name" : "mickey", "fortune" : "00000000000000100000" }


> db.test123.find({ "fortune" : {$gte: "00000200000000000000"}});
{ "_id" : ObjectId("4f87e142f1573cffecd0f65e"), "name" : "bruce wayne", "fortune" : "00000200000000000000" }


> db.test123.find({ "fortune" : {$lt: "00000200000000000000"}});
{ "_id" : ObjectId("4f87e150f1573cffecd0f65f"), "name" : "donald", "fortune" : "00000150000000000000" }
{ "_id" : ObjectId("4f87e160f1573cffecd0f660"), "name" : "mickey", "fortune" : "00000000000000100000" }

查询/排序将自然地工作,因为 mongodb 按字典顺序比较字符串。但是,要对您的数据执行其他数字操作,您必须在数据处理脚本(PHP、Python、Ruby 等)中编写自定义逻辑

对于查询和数据存储,这个字符串版本应该很好。

于 2012-04-13T08:07:44.713 回答
0

不幸的是,您对数组比较的假设是不正确的。例如,查询所有小于 3 的数组值 ({array:{$lt:3}}) 的范围查询将返回至少一个元素小于 3 的所有数组,而不管元素的位置如何。因此,您的方法将行不通。

什么有效,但不太明显,将二进制 blob 用于非常大的整数,因为它们是按字节顺序比较的。这需要您为整数设置一个上限,但这应该相当简单。您可以使用 BinData(subType, base64) 表示法在 shell 中对其进行测试:

db.col.find({fortune:{$gt:BinData(0, "e8MEnzZoFyMmD7WSHdNrFJyEk8M=")}})

所以你所要做的就是创建方法来将你的大整数从字符串转换为二补码二进制,然后你就设置好了。祝你好运

于 2012-04-13T08:18:19.523 回答