How to Find Nearest Location Using Latitude and Longitude In Mongoose 2022
Sometimes you need to find the nearest location using latitude and longitude within a radius.
In this article, we gonna learn how to use mongoose orm to find nearby locations.
We need to use GeoJSON objects for geospatial queries.
Ref:- https://mongoosejs.com/docs/geojson.html
Point Schema:- The most simple structure in GeoJSON is a point.
{
"type" : "Point",
"coordinates" : [-122.5, 37.7]
}
Note:- that longitude comes first in a GeoJSON coordinate array, not latitude.
models/user.model.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema(
{
name: String,
status: {
type: Boolean,
default: true
},
location: {
type: {
type: String,
enum: ['Point']
},
coordinates: {
type: [Number]
}
}
},
{
timestamps: true
}
);
UserSchema.index({ location: "2dsphere" });
const User = mongoose.model("User", UserSchema);
module.exports = User;
Insert Dummy Users
await User.insertMany([
{
name: "User 1",
location: {
type: 'Point',
coordinates: [79.821602, 28.626137]
}
},
{
name: "User 2",
location: {
type: 'Point',
coordinates: [79.821091, 28.625484]
}
},
{
name: "User 3",
location: {
type: 'Point',
coordinates: [79.817924, 28.625294]
}
},
{
name: "User 4",
location: {
type: 'Point',
coordinates: [79.814636, 28.625181]
}
},
{
name: "User 5",
location: {
type: 'Point',
coordinates: [79.810135, 28.625044]
}
},
{
name: "User 6",
location: {
type: 'Point',
coordinates: [79.808296, 28.625019]
}
}
]);
Here is an example for finding nearby 5 users within 1 km.
Example using aggregate()
const latitude = 28.626137;
const longitude = 79.821602;
const distance = 1;
const unitValue = 1000;
const users = await User.aggregate([
{
$geoNear: {
near: {
type: 'Point',
coordinates: [longitude, latitude]
},
query: {
status: true
},
maxDistance: distance * unitValue,
distanceField: 'distance',
distanceMultiplier: 1 / unitValue
}
},
{
$project: {
_id: 1,
distance: 1
}
},
{
$sort: {
distance: 1
}
},
{ $limit: 5 }
]);
Note:- Inside the query object you can pass your conditions. in the above example, I am searching only active users. you can also remove this query object.
If your collection has multiple 2d and/or multiple 2dsphere indexes, you must use the key option to specify the indexed field path to use.
$geoNear: {
near: {
type: 'Point',
coordinates: [longitude, latitude]
},
query: {
status: true
},
maxDistance: distance * unitValue,
distanceField: 'distance',
distanceMultiplier: 1 / unitValue,
key: 'location'
}
Note:- In the case of miles just replace unitValue 1000 with 1609.3
Miles - 1609.3
Kilometer - 1000
you can also round the distance in query.
{
$project: {
_id: 1,
distance: {
$round: ["$distance", 2]
}
}
}
Example using static function
We can also make it reusable by defining this as a static function inside the model.
UserSchema.static('findByDistance', function(longitude, latitude, distance, unit = 'km') {
const unitValue = unit == "km" ? 1000 : 1609.3;
return this.aggregate([
{
$geoNear: {
near: {
type: 'Point',
coordinates: [longitude, latitude]
},
query: { status: true },
maxDistance: distance * unitValue,
distanceField: 'distance',
distanceMultiplier: 1 / unitValue
}
},
{
$project: {
_id: 1,
distance: 1
}
},
{
$sort: {
distance: 1
}
},
{ $limit: 5 }
]);
});
Note:- I have passed km as the default unit. so you don't need to pass in case of kilometer calculation.
Now in the controller, you can call this function.
const users = await User.findByDistance(longitude, latitude, distance);
In the case of miles.
const users = await User.findByDistance(longitude, latitude, distance, 'm');
Example using find()
const latitude = 28.626137;
const longitude = 79.821602;
const distance = 1;
const unitValue = 1000;
const users = await User.find({
location: {
$near: {
$maxDistance: distance * unitValue, // distance in meters
$geometry: {
type: 'Point',
coordinates: [longitude, latitude]
}
}
}
})
.select('_id')
return res.json(users)
Note:- $near by default sorts documents by distance.
Checkout my full mongoose-geo example.
https://github.com/ultimateakash/mongoose-geo
If you facing any issues. don't hesitate to comment below. I will be happy to help you.
Thanks.
Leave Your Comment