查询MongoDB中的场景

时间:2016-11-29 19:00:47

标签: java mongodb mongodb-query mongodb-java

作为我在mongoDB中的新手,我想知道以下问题:我的文档中有一个字段(我们称之为fieldA)。该字段的值存储为数字表示的十六进制字符串。是否有可能根据数值表示检索fieldA值落在给定值范围内的那些文档的子集?我假设该字段存储为字符串,mongoDB会根据给定的查询限制按字典顺序fieldA进行比较,这与我的需求不一致。

让我们说我的文档范围是:fieldA >= "0x12f"fieldA <= "0x12ea"在这种情况下我假设mongoDB会按字典顺序进行比较以做出决定,但在这种情况下,我希望基于数值进行比较。

1 个答案:

答案 0 :(得分: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