В MongoDB можно выполнить запросы диапазона по шестнадцатеричному размеру более 64 бит, если вы преобразуете шестнадцатеричную строку в двоичные данные. Класс Java BigInteger позволяет это.
Рассмотрим следующий код для вставки и запроса шестнадцатеричные значения в двоичном
private static void bigIntTest(MongoCollection<Document> bigIntCollection) {
// BigInteger cannot parse 0x, so it must be stripped off
// the "16" argument represent base 16 radix
BigInteger floor = new BigInteger("0x12f".substring(2), 16);
BigInteger ceiling = new BigInteger("0x12ea".substring(2), 16);
BigInteger between = new BigInteger("0x555".substring(2), 16);
// The toByteArray() method on BigInteger returns a byte array
// Containing the two's-complement representation of this BigInteger.
// MongoDB will store the byte array as a binary data field
bigIntCollection.insertOne(new Document("value", floor.toByteArray()));
bigIntCollection.insertOne(new Document("value", between.toByteArray()));
bigIntCollection.insertOne(new Document("value", ceiling.toByteArray()));
rangeQuery(bigIntCollection, floor, ceiling);
// Test with values greater than Long.MAX_VALUE
BigInteger newFloor = new BigInteger("8000000000000000", 16);
BigInteger newBetween = new BigInteger("1dcd64ffffffffffe58250e3", 16);
BigInteger newCeiling = new BigInteger("4563918244f3fffff538dcfb7617ffff", 16);
List<Document> newDocuments = Arrays.asList(new Document[] { new Document("value", newFloor.toByteArray()),
new Document("value", newBetween.toByteArray()), new Document("value", newCeiling.toByteArray()) });
bigIntCollection.insertMany(newDocuments);
rangeQuery(bigIntCollection, newFloor, newCeiling);
}
private static void rangeQuery(MongoCollection<Document> bigIntCollection, BigInteger floor, BigInteger ceiling) {
Document range = new Document("$gt", floor.toByteArray());
range.append("$lt", ceiling.toByteArray());
Document filter = new Document("value", range);
FindIterable<Document> find = bigIntCollection.find().filter(filter);
find.iterator().forEachRemaining(new Consumer<Document>() {
@Override
public void accept(Document t) {
byte[] data = ((Binary) t.get("value")).getData();
System.out.println(new BigInteger(data).toString(16));
}
});
}
Второй набор шестнадцатеричных значений превышает Long.MAX_VALUE
и он все еще работал как шарм. Тем не менее я бы рекомендовал провести обширное тестирование до использования этого метода в производстве, особенно если отрицательные числа возможны и вокруг границ переполнения. Полный код может быть найден here
Это решение поставляется с дополнительным предупреждением. При больших двоичных значениях индексация может стать дорогостоящей в отношении производительности и производительности. Обязательно просмотрите MongoDB docs по этой теме.
Я не думаю, что это возможно. Почему бы не иметь другое поле с соответствующим десятичным числом и использовать его для запросов диапазона? – cjungel
@cjungel, что было бы хорошим решением да. Но я обеспокоен тем фактом, что значение этого поля увеличивается настолько быстро, что может попасть в точку, когда представление десятичного числа не может справиться с этим. И в основном это было причиной того, что поле было спроектировано именно так. Поскольку я программирую на Java, я рассматривал Long как численное представление, но да, обеспокоенный этим фактом. –
Оба java и mongo поддерживают 64-битные целые числа. Требуется ли вам поддерживать большие номера? Если этого достаточно для вашего домена, вы можете использовать собственные индексы и выполнять эффективные запросы диапазона. Если вам абсолютно нужны большие числа, вы можете представить их как строки с фиксированной длиной (с предшествующими 0). Таким образом, вы можете представлять произвольно большие числа, которые все еще могут использовать собственные индексы для выполнения запросов диапазона, учитывая, что буквенно-цифровое упорядочение строк будет правильным в вашем случае. – cjungel