Geospatial Query with MongoDB and Node.js

Hasn’t been a long time when i started working with Wearetech.io and my first challenge was on. Sweet!

If you want to learn more about Wearetech.io, check the site and our Github repo.

Now on the fun part. We have a use case where an individual would be able to register on our site as a City Curator.

He could search for his City and if he wouldn’t find it in our database he would register it. When the next candidate comes in, he searches for his place and if it would be inside a 10 kilometers range of an already registered city we would deny it, since we wouldn’t want to have city calendars overlapping with each other.

When Thanasis started building Wearetech.io he decided to go with MongoDB. So in order to create the above scenario, MongoDB Geospatial Queries to the rescue!

MongoDB supports two types of Geospatial Queries indexing.

  • The spherical (2dSphere), that would allow you to store shapes made of points (coordinates) and then make comparisons with them like intersection, etc.
  • The flat (2d), that would store single points and then come up with their distances.

Your choice will affect your development a lot down the road, so think wisely.

Now on the code side, we will use Mongoose to shape our models. Here’s the most simple one.


var mongoose     = require('mongoose');
var Schema     = mongoose.Schema;

var CitySchema   = new Schema({
  name: String,
  geo: {
    type: [Number],
    index: '2d'
  }
});

module.exports = mongoose.model('City', CitySchema);

Now we can start populating our DB like this


var City = require('./app/models/city');

var cityModel     = new City(); 
cityModel.name = req.body.name; 
cityModel.geo    = [ req.body.lat, req.body.lng ]; 

cityModel.save(function (err) {
  if (err)
    res.send(err);

  res.json({});
});

And now on the fun part

var distance = 1000 / 6371;

var query = City.findOne({'geo': {
  $near: [
    req.body.lat,
    req.body.lng
  ],
  $maxDistance: distance

  }
});

query.exec(function (err, city) {
  if (err) {
    console.log(err);
    throw err;
  }

  if (!city) {
    res.json({});
  } else {
    console.log('Cant save: Found city:' + city);
    res.json(city);
 }

});

Our distance is in radians metric system and you can find more on how to calculate it here.

Here is a demo of it. Try searching your City. If it’s available register it and then try to find a place inside a 10 kilometers range of your previeus registered City.

Hope you will find it interesting. Comments?

Advertisements

Leave a comment.

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s