Recently I was intrigued about a project discussion in which a high volume REST API was needed to store and retrieve location based information. A performant solution was need that could work with big datasets, atleast containing a few million entries.
I haven’t done much work in the Geospatial area but I thought this could be an interesting use case to get my hands dirty to learn something new. The requested API needed to be able to store location points for a subject (person). On the other hand these locations needed to be retrieved based on their proximity to a certain point (latitude and longitude).
After stumbling upon MongoDB’s support for GeoJSON, a format for encoding a variety of geographic data structures, it looked like a perfect match for this use case. High volume and performance shouldn’t be a problem for MongoDB. A GeoJSON Point (latitude, longtitude) was already supported in MongoDB since v2.4, a lot of other features and improvements have been added since then in the current v3.0. Sounds impressive, no?
I decided to start a quick prototype has contained two methods:
GET
/locations
that has four query parameters.lat
: latitude,long
: longtitude,d
: distance from the location ands
: subject.POST
/locations
that has one query parameter.s
: subject and abody
that contains a list of locations for this specific subject.
The technologies for this prototype are:
- Spring Boot
- Spring Data MongoDB
- Gradle
Create a MongoDB database and add spatial index
If you installed MongoDB commandline, define your database and create an index:
Generate a basic project
Head over to Spring Initializer, or if you are using IntelliJ you can just choose to create a new Spring Boot application, and choose Spring Web, Spring Data MongoDB and Gradle. You should end up with a build.gradle
something along the lines of:
build.gradle
Since the Gradle Wrapper is recommended by the documentation I also used it.
Add Spring Data MongoDB repository
Spring Data JPA is basicially a standard in most of my projects, so I was happy to see that there is also a Spring Data MongoDB project and it already also has support for Geospatial queries!
First let’s create a simple LocationEntity
which will be stored in MongoDB. For the sake of brevity I left out the getters/setters/equals/hashcode, you can find the full source on GitHub:
LocationEntity.java
Next we need a Spring Repository that will actually query for all locations for a certain subject and a proximity near a location. This is where all the heavy lifting (magic?) has to happen.
LocationRepository.java
That’s all you need, Spring Data will take care of everything based on the method name. That’s awesome, right? You pass a subject, a certain Point (longitude and latitude) and how far in distance it should look from that certain point in miles or kilometers. Spring magic at its best.
Implementing REST endpoints
As we defined before, we’ll need to two endpoints to retrieve the locations based on the repository that we just created and also create new LocationEntity entries. Let’s start with retrieving the locations:
LocationResource.java
Spring gives you a nice RestController
annotation that will make sure all the methods in the class are annotated with ResponseBody
. The only this this method do is have a few query parameters and use them to call our LocationRepository
. We have to define the metric we want to use for the distance
parameter, in our case we’ll use kilometers.
Next, we want to add locations for a certain subject
LocationResource.java
The LocationEntry
POJO is an object that only contains latitude and longitude, since that’s all we need for a location that will be added. Based on this POJO we created a new GeoJsonPoint
to store it in MongoDB.
With these few steps I was able to create a Geospatial Location based API prototype within a few hours, mostly spent on doing research on MongoDB and Spring Data MongoDB capabilities. I’m happy that I now know MongoDB is capable of quite a bit of Geospatial things, and that it is quite easy to use as well.
Hope you learned something new as well! You can find the source code for this example on GitHub.