Mongoose find geo points by radius

Viewed 3929

I tried found geo points by radius, I found tutorial explain how to does it.

Snippet from tutorial:

First we need to create a schema. The docs give us some examples on how to store geospatial data. We are going to use the legacy format for our example. It’s recommended to store the longitude and latitude in an array. The docs warn use about the order of the values, longitude comes first.

var LocationSchema = new Schema({  
  name: String,
  loc: {
  type: [Number],  // [<longitude>, <latitude>]
  index: '2d'      // create the geospatial index
 }
});

First you can create a method in your controller that can look something like this:

findLocation: function(req, res, next) {  
    var limit = req.query.limit || 10;

    // get the max distance or set it to 8 kilometers
    var maxDistance = req.query.distance || 8;

    // we need to convert the distance to radians
    // the raduis of Earth is approximately 6371 kilometers
    maxDistance /= 6371;

    // get coordinates [ <longitude> , <latitude> ]
    var coords = [];
    coords[0] = req.query.longitude;
    coords[1] = req.query.latitude;

    // find a location
    Location.find({
      loc: {
        $near: coords,
        $maxDistance: maxDistance
      }
    }).limit(limit).exec(function(err, locations) {
      if (err) {
        return res.json(500, err);
      }

      res.json(200, locations);
    });
}

Reference to tutorial: How to use Geospatial Indexing in MongoDB with Express and Mongoose

After implemented source from tutorial to my project I didn't receive from database correct points by radius (points were not inside radius).

My question is how can I receive geo points by radius ( kilometers or meters don't matter)?

Thanks, Michael.

3 Answers

Not sure how relevant this still is, as it was posted in 2016, but I had a similar issue. I'm using the following configuration:

  • MongoDB: 4.4.5
  • mongoose: 5.12.3
  • Node.js: 15.9.0

I had to split the kilometer by radians to get the radius. So if I want everything in a one kilometer radius I have to calculate 1/6371.

Also, please note that Mongo (and mongoose) coordinates always have to be a numeric array with the longitude BEFORE the latitude. That goes for both the object stored in the database as well as the query.

const km = 1;
const radius = km / 6371;

const longitude = 25;
const latitude = 20;

const area = { center: [longitude, latitude], radius: radius, unique: true, spherical: true };
query.where('geo').within().circle(area);

Remember that your loc has to be a Point Schema (geojson), as specified in mongoose docs.

For example:

const pointSchema = new mongoose.Schema({
  type: {
    type: String,
    enum: ['Point'],
    required: true
  },
  coordinates: {
    type: [Number],
    required: true
  }
});

const locationSchema = new mongoose.Schema({
  name: String,
  loc: {
    type: pointSchema,
    required: true
  }
});

Finding the posts in particular radius

const { zipcode, distance } = req.params;

console.log(distance);
const radius = distance / 3963; // convert distance of KM in

var loc = [];
loc =  [longitude, latitude]; // center point 
const bootcamps = await Bootcamp.find({
location: {
  $geoWithin: {
    $centerSphere: [loc, radius],
  },
},
});
Related