13 min read

(For more resources on PHP and MongoDB, see here.)

A geolocation primer

The term geolocation refers to the act of locating the geographic position of a person, a place, or any place of interest. The geographic position of the object is determined mainly by the latitude and longitude of the object, sometimes its height from sea level is also taken into account. In this section, we are going to learn about different techniques that location- based applications use to determine a user’s location. You may skip this section if you are already familiar with them, or if you just cannot wait to get started coding!

Methods to determine location

There are several ways to locate the geographic position of a computing device. Let’s briefly learn about the most effective ones among them:

  • Global Positioning System (GPS ): Nowadays, tech savvy people carry GPS-enabled smartphones in their pockets. Devices like these act as GPS receivers; they constantly exchange information with GPS satellites orbiting the Earth and calculate their geographic position. This process is known as trilateration . This is perhaps the most accurate way to determine location, as of today.
  • Cellphone tracking: Each cellphone has a Cell ID assigned to it that uniquely identifies it in a particular cellular network. In a process known as cellular triangulation , three base stations (cellphone towers) are used to correctly identify the latitude and longitude of the cellphone identified by the Cell ID. This method is more accurate in urban areas, where there are more cellphone towers close to each other, than in rural areas.
  • IP address: Internet service providers are given blocks of IP addresses based on a country/city/region. When a user visits a website, the website could take a look at his IP address and consult an database that stores location data against IP addresses (it might be either an internal database or provided by a third-party service) to get the location of the user. Accuracy of this approach depends on the accuracy of the database itself. Also, if the user is behind a proxy server, the application will see the IP address of the proxy server, which could be located in a different region than the user.
  • Wi-Fi MAC address tracking: A Wi-Fi access point has a MAC (Media Access Control) address assigned to it, which is globally unique. Some location-based services use this to identify the location of the Wi-Fi router, and therefore, the location of users on that Wi-Fi LAN. In principle, it works in the same way IP address-based geolocation does. Google has an API that gives location information (latitude, longitude, and so on) when provided with a MAC address.

If you are curious to learn more about how geolocation works, How Stuff Works has a comprehensive article on it available at http://electronics.howstuffworks.com/ everyday-tech/location-tracking.htm.

Detecting the location of a web page visitor

When building a location-aware web application, the first part of the problem to be solved is to get the location of the user visiting the web page. We have covered geolocation techniques in the previous section, now it is time to see them in action.

The W3C Geolocation API

We are going to use the W3C Geolocation API for locating the visitors to our web page. The W3C Geolocation API provides a high-level interface for web developers to implement geolocation features in an application. The API takes care of detecting the location using one or more methods (GPS, Cell ID, IP address). The developers do not have to worry about what is going on under the hood; they only need to focus on the geographic information returned by the API! You can read the whole specification online at http://www.w3.org/TR/ geolocation-API/.

Browsers that support geolocation

The following table lists the browsers that support the W3C Geolocation API:

Browser

Version

Google Chrome

5.0+

Mozilla Firefox

3.5+

Internet Explorer

9.0+

Safari

5.0+

Opera

10.6+

iPhone

3.1+

Android

2.0+

Blackberry

6.0+

Make sure you use one of these browsers when you try the practical examples in this article.

Time for action – detecting location with W3C API

In this section, we are going to build a web page that detects the location of a visitor using the Geolocation API. The API will detect the latitude and longitude of the user who loads the page in his browser. We are going use that information on a map, rendered dynamically using the Google Maps API:

  1. Fire up your text editor and create a new HTML file named location.html. Put the following code in it:
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xml_lang="en"
    lang="en">
    <head>
    <meta http-equiv="Content-Type" content="text/html;
    charset=utf-8"/>
    <link rel="stylesheet" href="styles.css"/>
    <style type="text/css" media="screen">
    div#map {
    width:450px;
    height: 400px;
    }
    </style>
    <title>Locating your position</title>
    </head>

    <body>
    <div id="contentarea">
    <div id="innercontentarea">
    <h2>Locating your position</h2>
    <div id="map"></div>
    </div>
    </div>
    <script type="text/javascript"
    src="http://maps.googleapis.com/maps/api/js?sensor=false">
    </script>
    <script type="text/javascript" src="geolocation.js">
    </script>
    </body>
    </html>

  3. Create another file named geolocation.js and put the following JavaScript code in it:
  4. var mapContainer = document.getElementById('map');
    var map;
    function init() {
    //Google map settings (zoom level, map type etc.)
    var mapOptions = {zoom: 16,
    disableDefaultUI: true,
    mapTypeId: google.maps.MapTypeId.ROADMAP};
    //map will be drawn inside the mapContainer
    map = new google.maps.Map(mapContainer, mapOptions);
    detectLocation();
    }
    function detectLocation(){
    var options = { enableHighAccuracy: true,
    maximumAge: 1000, timeout: 30000};
    //check if the browser supports geolocation
    if (window.navigator.geolocation) {
    //get current position
    window.navigator.geolocation.getCurrentPosition(
    drawLocationOnMap,
    handleGeoloacteError,
    options);
    } else {
    alert("Sorry, your browser doesn't seem to support
    geolocation :-(");
    }
    }
    //callback function of getCurrentPosition(), pinpoints location
    //on Google map
    function drawLocationOnMap(position) {
    //get latitude/longitude from Position object
    var lat = position.coords.latitude;
    var lon = position.coords.longitude;
    var msg = "You are here: Latitude "+lat+", Longitude "+lon;
    //mark current location on Google map
    var pos = new google.maps.LatLng(lat, lon);
    var infoBox = new google.maps.InfoWindow({map: map,
    position:pos,
    content: msg});
    map.setCenter(pos);
    return;
    }
    function handleGeoloacteError() {
    alert("Sorry, couldn't get your geolocation :-(");
    }
    window.onload = init;

  5. Load the location.html page in your browser. When the browser asks for permission to allow the page to access your location, click Yes/OK/Allow:

     

  6. (Move the mouse over the image to enlarge.)

     

  7. Once you allow the page to access your location, it renders a map that shows your current location on it, along with the geographic coordinates:

What just happened?

We built a web page and added JavaScript code that detects the latitude and longitude of the user who loads the page in his browser. The API needs the user’s permission to get his geographic information. So when the page loads, it prompts the user to specify whether or not he will allow the page to get his location. If the user agrees, the JavaScript code executes and gets his geographic coordinates using the W3C Geolocation API. Then it renders a small map using the Google Maps API, and highlights the user’s location on the map.

The Geolocation object

The Geolocation object implements the W3C Geolocation API. The JavaScript engine uses this object to obtain geographic information of the computer or phone on which the browser is running. Geolocation is a property of the Browser object (window.navigator), accessed as window.navigator.geolocation. In our example, we detect if the browser has geolocation capabilities by accessing this object, and notify the user if the browser fails the test:

//check if the browser supports geolocation
if (window.navigator.geolocation) {
window.navigator.geolocation.getCurrentPosition(
drawLocationOnMap,
handleGeoloacteError,
options);
} else {
alert("Sorry, your browser doesn't seem to support geolocation.");
}

The getCurrentPosition() method

The location information is obtained invoking the getCurrentPosition() method on the Geolocation object.

 

getCurrentPostition(callbackOnSuccess, [callbackOnFailure, options])

 

The argument callbackOnSuccess is a reference to a callback function. It is executed when the getCurrentPosition() method successfully determines the geolocation. This is a mandatory argument. callbackOnFailure is an optional argument, a callback function for handling failure to get the geolocation. options represents the PositionOptions object, which specifies optional configuration parameters to the method. The PositionOptions object has the following properties:

  • enableHighAccuracy : Tells the API to try its best to get the exact current position. It is set to false by default. When set to true, the API response tends to be slower.
  • maximumAge : If API responses are cached, this setting specifies that the API will not use the cached responses older than maximumAge milliseconds.
  • timeout : The timeout value in milliseconds to receive the API response.

In our example, we used the drawLocationOnMap() method as a callbackOnSuccess function , which draws a map and pinpoints the location on it (we will walkthrough it shortly). The handleGeoloacteError() method notifies the user of any error while getting the position:

window.navigator.geolocation.getCurrentPosition(
drawLocationOnMap,
handleGeoloacteError,
options);

Drawing the map using the Google Maps APTI

The Google Maps APTIis a popular JavaScript API for drawing maps on a web page. This API has methods to highlight objects on the rendered map. We can access the API methods by adding the following script tag in the web page (as we did in the location.html file):

<script type="text/javascript"
src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>

If you are on a GPS-enabled device, set the sensor parameter to true, as follows:

When the script is loaded, we can initiate the map drawing by instantinating the google. maps.Map object . The Map object takes a DOM object as its first parameter; the map will be rendered inside this DOM. It also takes an optional JSON object that specifies configurations for the map (zoom level, map type, and so on):

var mapContainer = document.getElementById('map');
var mapOptions = {zoom: 16,
disableDefaultUI: true,
mapTypeId: google.maps.MapTypeId.ROADMAP};
map = new google.maps.Map(mapContainer, mapOptions);

Now, let’s focus on the drawLocationOnMap() function in the geolocation.js file, which is the callback function of the getCurrentPosition() method . As we know, this method gets called when the W3C API successfully locates the position; it receives a Position object as its argument. This object holds all the geolocation data returned by the API. The Position object holds a reference to the Coordinates object (accessed by the property coords). The Coordinates object contains geographical coordinates such as latitude, longitude, altitude, and so on of the location:

function drawLocationOnMap(position) {
var lat = position.coords.latitude;
var lon = position.coords.longitude;

var msg = "You are here: Latitude "+lat+", Longitude "+lon;
……………………………………………………………………………………………………………………………………………………………
}

After we get the latitude and longitude values of the coordinate, we set it as the center of the map. We also display an information box with a message saying, You are here on the map!

function drawLocationOnMap(position) {
var lat = position.coords.latitude;
var lon = position.coords.longitude;
var msg = "You are here: Latitude "+lat+", Longitude "+lon;
var pos = new google.maps.LatLng(lat, lon);
var infoBox = new google.maps.InfoWindow({map: map,
position:pos,
content: msg});
map.setCenter(pos);

return;
}

Get to know Google Maps API
We are going to use the Google Maps API in the upcoming examples as well. You might consider familiarizing yourself with it by reading some of its online documentation at http://code.google.com/apis/maps/ documentation/javascript/basics.html.

Geospatial indexing

We can now turn our attention to the main topic of this article—geospatial indexing . A geospatial index is a special kind of index, designed specifically with location queries in mind, so you can perform queries like “Give me the closest n objects to my location”. Geospatial indexing essentially turns your collection into a two-dimensional map. Each point of interest on that map (each document in the collection) is assigned a special value named geohash. Geohashing divides the coordinate system into hierarchical buckets of grids; the whole map gets divided into smaller quadrants. When you look for objects nearest to a point (x,y) on the map, MongoDB calculates the geohash of (x,y) and returns the points with the same geohash. I am not going to delve into much detail here on how it works, but if you are interested, I recommend you read MongoDB in Flatland (found at http://www.snailinaturtleneck.com/blog/2011/06/08/mongo-in-flatland/), an elaborate yet simple demonstration of how geospatial indexing works in MongoDB.

Indexes are generally applied on fields to make field lookups faster.

Time for action – creating geospatial indexes

Let’s see how we can build the geospatial index on a MongoDB collection:

  1. Launch the mongo interactive shell. Switch to a new database namespace called geolocation:
  2. $ ./mongodb/bin/mongo
    MongoDB shell version: 1.8.1
    connecting to: test
    > use geolocation
    switched to db geolocation
    >

  3. Insert a few documents in a collection named ?map. Each document must contain an embedded document with two fields, latitude and longitude:
  4. > db.map.insert({coordinate: {latitude:23.2342987,
    longitude:90.20348}})
    > db.map.insert({coordinate: {latitude:23.3459835,
    longitude:90.92348}})
    > db.map.insert({coordinate: {latitude:23.6743521,
    longitude:90.30458}})

  5. Create the geospatial index for the map collection by issuing the following command:
  6. >db.map.ensureIndex({coordinate: '2d'})

  7. Enter the next command to check if the index was created:
  8. > db.system.indexes.find()
    { "name" : "_id_", "ns" : "geolocation.map", "key" : { "_id" : 1
    }, "v" : 0 }
    { "_id" : ObjectId("4e46af48ffd7d5fd0a4d1e41"), "ns" :
    "geolocation.map", "key" : { "coordinate" : "2d" }, "name" : "
    coordinate _" }

What just happened?

We created a MongoDB collection named geocollection in a database named map. We manually inserted documents into the collection, each document contains some random latitude and longitude values in an embedded document named coordinate:

> db.map.findOne()
{
"_id" : ObjectId("4e46ae9bffd7d5fd0a4d1e3e"),
"coordinate" : {
"latitude" : 23.2342987,
"longitude" : 90.20348
}
}

After that, we built the geospatial index on the latitude/longitude pairs by calling the ensureIndex() method on the collection:

db.map.ensureIndex({coordinate: "2d"})

Next, we invoked the system.indexes.find() method that lists the indexes in the database. The index we created should be in that list:

> db.system.indexes.find()
{ "name" : "_id_", "ns" : "geolocation.map", "key" : { "_id" : 1 }, "v" :
0 }
{ "_id" : ObjectId("4e46af48ffd7d5fd0a4d1e41"), "ns" : "geolocation.map",
"key" : { "coordinate" : "2d" }, "name" : " coordinate _" }

Geospatial indexing – Important things to know

There are a few of things you must know about geospatial indexing:

  • There can be only one geospatial index for a MongoDB collection. You cannot have more than one geospatial index for a collection.
  • The index must be created for an embeded documendt or an array field of the document. If you build the index for an array field, the first two elements of the array will be considered as the (x,y) coordinate:
  • >db.map.insert({coordinate: [23.3459835, 90.92348]})
    >db.map.ensureIndex({coordinate: "2d"})

  • Ordering is important when you are storing coordinates. If you store them in the order (y,x) rather than (x,y), you will have to query the collection with (y,x).

Use arrays to store coordinates
When storing coordinates in a geospatially indexed field, arrays are preferable to embedded objects. This is because an array preserves the order of items in it. No matter what programming language you are using to interact with MongoDB, this comes in very handy when you do queries.

LEAVE A REPLY

Please enter your comment!
Please enter your name here