2012-04-13 3 views
0

Я хотел бы хранить в mongdb некоторые очень большие целые числа, в точности (несколько тысяч десятичных цифр). Разумеется, это не будет работать со стандартными типами, поддерживаемыми BSON, и я пытаюсь придумать наиболее изящное обходное решение, учитывая, что я хотел бы выполнять поиск диапазона и подобные вещи. Это требование исключает хранение целых чисел в виде строк, поскольку это делает поиск диапазона нецелесообразным.Как сравнить bson массивы (в mongodb/pymongo)?

Один из способов, который я могу представить, - это кодировать 2^32-расширение с использованием массивов (переменной длины) стандартных ints и добавить к этому массиву первую запись для длины самого массива. Таким образом, лексикографическое упорядочение на этих массивах соответствует обычному упорядочению сколь угодно больших целых чисел.

Например, в коллекции я мог иметь 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.

Затем я могу сделать что-то вроде, используя { «состояние»: 1} и на моей машине (с PyMongo) он возвращает их в порядке Френсис < < меня банкнота < < брюс Скруджа, как и ожидалось.

Однако, я делаю предположение, что я не видел документированное где-нибудь о том, как BSON массивах сравнения и поиски диапазона, кажется, не работают так, как я думаю, что (например,

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

не возвращает никакого документа, но я бы хотел, чтобы у Брюса и scrooge).

Может ли кто-нибудь мне помочь? Спасибо

+0

Оба решения, описанные ниже Дхрувом и Ремоном, требуют, чтобы я знал максимальную длину, и что я храню много нулевых дополнений. – user1199915

ответ

0

Вместо этого вы можете хранить левые заполненные строки, которые представляют точное целое число, равное удаче.

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

левая обивка нули обеспечит lexographical сравнения этих строк непосредственно соответствует их сравнениям в виде числовых значений также. Вы должны предположить безопасное максимально возможное значение удачи здесь, скажем, 20-значный номер, и подушечки в 0s соответственно Таким образом, образцы документов будут:

{"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 и т. Д.).

Для запросов и хранения данных эта строковая версия должна работать нормально.

0

К сожалению, неверное допущение по поводу сопоставления массива неверен. Запросы диапазона, которые, например, запрашивают для всех значений массива меньше 3 ({array: {$ lt: 3}}), возвращают все массивы, где хотя бы один элемент меньше трех, независимо от позиции элемента. Таким образом, ваш подход не будет работать.

Что работает, но немного менее очевидно, использует бинарные капли для ваших очень больших целых чисел, поскольку они сравниваются по байтам.Это требует, чтобы вы установили верхний предел для своих целых чисел, но это должно быть довольно простым. Вы можете проверить его в оболочке, используя BinData (подтип, base64) обозначения:

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

Так что все вы должны сделать, это создать методы для преобразования ваших больших целых чисел, скажем, строк до двух-дополняет двоичным и вы 'сброс. Удачи

Смежные вопросы