bson数组如何比较(在mongodb / pymongo中)?

时间:2012-04-13 07:06:24

标签: mongodb pymongo bson

我想在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和Scrooge McDuck的2 ^ 320。

然后,我可以使用{“fortune”:1}进行排序,并在我的机器上(使用pymongo)按照francis<的顺序返回它们。我<账单<布鲁斯< scrooge,正如所料。

然而,我假设我没有看到任何关于BSON阵列比较方式的记录,并且范围搜索似乎不像我想的那样工作(例如,

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

没有返回任何文件,但我希望布鲁斯和斯克鲁奇。

任何人都可以帮助我吗?感谢

2 个答案:

答案 0 :(得分: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等)中编写自定义逻辑

对于查询和数据存储,此字符串版本应该可以。

答案 1 :(得分:0)

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

什么工作,但有点不太明显,是使用二进制blob为你的大整数,因为这些是字节顺序比较。这需要你为整数设置一个高位限制,但这应该是相当简单的。您可以使用BinData(subType,base64)表示法在shell中测试它:

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

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