Reputation: 441
I am storing places in a Mongoose model (name + coords as [lng, lat]) and have a 2d index on it.
I want to get the nearest locations from a point (lng, lat) within a radius in km.
For this, I use mongoose's $near and $maxDistance parameters. The issue I am facing is that the radius does not seem to be precise, thus I get wrong results.
Here is my code for the geo search:
LocationModel.find({
loc: {
$near: coords,
$maxDistance: max_distance
}
}).exec(function(err, locations)
{
if(err)
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
res.json(locations);
});
I have two locations for my tests:
Place 1 : 6.614090000000033, 45.4203
Place 2 : 6.905578500000047, 45.4683226
Total distance : 23.36km
The max_distance for $maxDistance is calculated this way:
var max_distance = req.params.max_distance / 111.12;
When I provide the reference point as Place A, I only get results when I set the max_distance to 33km and over, and not 24km as it should be.
Can someone explain me what is wrong here? Maybe the 111.12 (which I found all over the Internet), or is it something else?
Thanks
Upvotes: 3
Views: 659
Reputation: 7228
1 degree is aprox 111 kms at equator, where your 111.12 comes from. But as we move away from the equator it becomes less due to the convergence of the meridians(longitude) as we approach the pole.
Degree Lat Lng
0° 110.574 km 111.320 km
15° 110.649 km 107.551 km
30° 110.852 km 96.486 km
45° 111.132 km 78.847 km
60° 111.412 km 55.800 km
75° 111.618 km 28.902 km
90° 111.694 km 0.000 km
You could use equirectangular approximation for this.
x = Δlat * cos (Δlng/2)
y = ΔLng
d = R ⋅ √x² + y²
where Δlat & Δlng in radians & R = radius of earth
Δlat is the difference between the 2 lats & Δlng that of lats
Upvotes: 1
Reputation: 539
Since you are talking about geolocations, I'd suggest these changes:
2dsphere
index instead of 2d
. This will ensure the search takes into consideration that the earth is not a 2d plane.So your schema should look something like this:
var LocationSchema = new mongoose.Schema({
name: String,
location: {
type: {
type: String,
default: "Point"
},
coordinates: {
type: [Number]
}
}
});
LocationSchema.index({ location: '2dsphere' });
Now you can use Model.geoNear to perform your query. To get your distance in kilometers, you need to use the distanceMultiplier
option with the radius of earth in kilometers as the value. Don't forget the { spherical: true }
flag.
Note: I've used it as part of an aggregation and its pretty accurate. It should work the same in the above case also. Mongoose documentation doesn't talk about it. Use this from MongoDB docs
Upvotes: 4