作为我在mongoDB中的新手,我想知道以下问题:我的文档中有一个字段(我们称之为fieldA
)。该字段的值存储为数字表示的十六进制字符串。是否有可能根据数值表示检索fieldA
值落在给定值范围内的那些文档的子集?我假设该字段存储为字符串,mongoDB会根据给定的查询限制按字典顺序fieldA
进行比较,这与我的需求不一致。
让我们说我的文档范围是:fieldA >= "0x12f"
和fieldA <= "0x12ea"
在这种情况下我假设mongoDB会按字典顺序进行比较以做出决定,但在这种情况下,我希望基于数值进行比较。
答案 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。