AlgorithmsCodilityPatternsTutorials

In the last tutorial we have seen how to setup sails with basic JWT authorization. Now it is time to define our main application logic.

We are going to take advantage of the Waterline ORM/ODM  to create models and setup some new routes. Waterline comes as a part of Sails.js framework, and is pretty convenient when it comes to rapid prototyping and building our models. So let’s get started!

MongoDB

For our database we are going to use MongoDB, a document database with built in geospatial querying capabilities. Waterline is database agnostic, so we could have easily gone with a table based database like MySQL or PostreSQL, or even a graph database like Neo4j. For a complete list of supported adapters, visit the docs.

First we are going to need MongoDB, so lets install it via https://www.mongodb.com/download-center#community. Try running it as a service, as it will make your life easier later on. After successful installation, you are going to need a client. There are numerous options, but i went with an electron based app imaginatively called MongoClient that leverages Meteor.js for its heavylifting. After installing your client and starting your MongoDB, the only default database is test, so be sure to create another one via CLI command ‘use my_shiney_new_db’ or via client. I named my db ‘discovery’ as this is the working title of our project.

Now it is time to connect our sails app with mongo. First we need to install the Waterline sails-mongo adapter

Now we got our mongo adapter, so lets configure it in config/connections.js

Waterline

Sails has some convenient CLI comands. Such as ‘generate api’ that will create an empty model and controller for you, so lets use it to create our Pin.

Now lets head to our Pin.js model and define some basic properties.

Notice we defined a one-to-many (basicaly a foreign key) relationship with our User model simply by stating it as a property, and a many-to-many relationship via claimedPins property. As one user can claim many pins, and one pin can be claimed by many users, we are storing that data in an intermediary table containing pin_id column and user_id column, by defining a many to many relationship. More on the supported Waterline ORM/ODM associations can be found here.

Now head to your User.js model and define the claimedPins property.

Allright, now that we have our models defined, time to sprinkle some pin-finding magic on our app. Before MongoDBv2.4 geospatial data was stored in coordinate pairs but now we have a brand new spec available, GeoJSON storage and queries. As stated in the docs
MongoDB supports the following GeoJSON objects:

  • Point
  • LineString
  • Polygon
  • MultiPoint
  • MultiLineString
  • MultiPolygon
  • GeometryCollection

For now, we are going to be using only Point,  but it is nice to know what is available. So, back to our Pin.js model to define a coordinates property, according to the spec:

For now, being db agnostic and all, Waterline does not provide an out of the box solution for geospatial queries and indexing, but extending the adapter is easy enough. In your config/bootstrap.js file place the following:

By simply stating that pin collection property should have a 2dsphere index in case it is called coordinates we have solved our problem. Note that this could have weird or no effects if we decided to switch our db to MySQL for example.

Now all that is left is to populate the database with some random pins, provide a method to retrieve them according to position from a given distance. Open PinController.js and add the following two methods

Dont forget to add these two methods to our routes.js config

Now open your postman or whatever you use for testing your API and create some pins. as we are currently creating the pins with pseudo random coordinates(

), try finding pins like this

just be sure to post with a JWT, or remove our isAuthorized policy from config/policies.js