I have the following query that is kind of like a reverse range lookup:
db.ip_ranges.find({ $and: [{ start_ip_num: { $lte: 1204135028 } }, { end_ip_num: { $gt: 1
The trick is to use a $lte and a sort. I got the query down to a few ms.
I had the exact same problem - finding which CIDR block matched a particular IP address. I also tried using $gte and $lte and was getting 10 second response times.
I solved the problem in a different way. Note that the CIDR blocks (the IP address ranges) in the MaxMind database don't overlap. Each IP address will at most match one result. So all you need to do is find the CIDR block with the largest start_ip_num that is less than the particular IP address. Then verify in application code that the end_ip_num is greater than the particular IP address.
Here's the code (using the node MongoDB client):
// Convert IP address to base 10.
var ipToDecimal = function (ipAddress) {
var split = ipAddress.split('.');
return (split[0] * 16777216) + (split[1] * 65536) + (split[2] * 256) + (+split[3]);
};
var ipAddress = '1.2.3.4';
var ipDecimal = ipToDecimal(ipAddress);
db.ip_addresses.find({start_ip_num: {$lte: ipDecimal}}, {_id: 0, country_code: 1, end_ip_num: 1}, {limit: 1, sort: [['start_ip_num', -1]]}).toArray(function (error, ipAddresses) {
if (ipAddresses[0] && ipAddresses[0]['end_ip_num'] >= ipDecimal) {
console.log('IP address found: ', ipAddresses[0]['country_code']);
} else {
console.log('IP address not found.');
}
});
Be sure to create an index on start_ip_num.