How to optimize MongoDB query with both $gt and $lte?

后端 未结 4 1963
后悔当初
后悔当初 2021-02-07 23:53

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         


        
4条回答
  •  自闭症患者
    2021-02-08 00:27

    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.

提交回复
热议问题