java - MongoDB 中的查询场景

标签 java mongodb mongodb-query mongodb-java

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

假设我的文档范围是:fieldA >= "0x12f"fieldA <= "0x12ea"在这种情况下,我假设 mongoDB 会按字典顺序比较来做出决定,但在这种情况下,我想根据数值进行比较。

最佳答案

在 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

关于java - MongoDB 中的查询场景,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40873736/

相关文章:

java - 如何使用java在mongodb中搜索文档并从中删除字段?

java - 从java发送命令到终端,其中包含空格

java - Android 8+ -如何在 android 中以编程方式连接到 wifi 网络?

node.js - 蒙哥错误: Econnrefused

java - 无法使用 spring 数据连接到基于 MongoDB Atlas 的数据库

node.js - 错误 'Cannot apply $pull to a non-array value'

MongoDB 获取当前日期的文档

java - MongoDB 奇怪的行为,orOperator

java - 如何在本地使用 spring-cloud-starter-aws 运行应用程序?

java - 如何实现单向一对多自引用关系?