2016-11-29 7 views
1

как я новичок в mongoDB, мне было интересно о следующей проблеме: в моем документе есть поле (давайте позвоним fieldA). Значение этого поля сохраняется как шестнадцатеричная строка численного представления. Можно ли получить подмножество тех документов, где значение fieldA падает в диапазоне значений значений, основанных на численном представлении? Я предполагаю, что, поскольку это поле хранится как строка, mongoDB сравнивает лексикографически fieldA в соответствии с заданными пределами запроса, что бы противоречило моим потребностям.Сценарий запроса в MongoDB

Скажем, мой диапазон документов: fieldA >= "0x12f" и fieldA <= "0x12ea" В этом случае я предполагаю, что MongoDB бы сравнить лексически принимать решения, но в данном случае я хотел бы сравнить на основе численных значений.

+0

Я не думаю, что это возможно. Почему бы не иметь другое поле с соответствующим десятичным числом и использовать его для запросов диапазона? – cjungel

+0

@cjungel, что было бы хорошим решением да. Но я обеспокоен тем фактом, что значение этого поля увеличивается настолько быстро, что может попасть в точку, когда представление десятичного числа не может справиться с этим. И в основном это было причиной того, что поле было спроектировано именно так. Поскольку я программирую на Java, я рассматривал Long как численное представление, но да, обеспокоенный этим фактом. –

+0

Оба java и mongo поддерживают 64-битные целые числа. Требуется ли вам поддерживать большие номера? Если этого достаточно для вашего домена, вы можете использовать собственные индексы и выполнять эффективные запросы диапазона. Если вам абсолютно нужны большие числа, вы можете представить их как строки с фиксированной длиной (с предшествующими 0). Таким образом, вы можете представлять произвольно большие числа, которые все еще могут использовать собственные индексы для выполнения запросов диапазона, учитывая, что буквенно-цифровое упорядочение строк будет правильным в вашем случае. – cjungel

ответ

0

В 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 по этой теме.

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