In this recipe, we will see what geospatial queries are and then see how to apply these queries on flat planes. We will put it to use in a test map application.
Geospatial queries can be executed on data in which geospatial indexes are created. There are two types of geospatial indexes. The first one is called the 2D indexes and is the simpler of the two, it assumes that the data is given as x,y coordinates. The second one is called 3D or spherical indexes and is relatively more complicated. In this recipe, we will explore the 2D indexes and execute some queries on 2D data. The data on which we are going to work upon is a 25 x 25 grid with some coordinates representing bus stops, restaurants, hospitals, and gardens.
Refer to the recipe Connecting to the single node using a Java client from Chapter 1, Installing and Starting the Server, for all the necessary setup for this recipe. Download the data file 2dMapLegacyData.json
and keep it on the local filesystem ready to import. Open a mongo shell connecting to the local MongoDB instance.
2dMapLegacyData.json
is present in the current directory.$ mongoimport -c areaMap -d test --drop 2dMapLegacyData.json
connected to: 127.0.0.1 Mon Mar 17 23:58:27.880 dropping: test.areaMap Mon Mar 17 23:58:27.932 check 9 26 Mon Mar 17 23:58:27.934 imported 26 objects
> db.areaMap.find()
This should give you the feel of the data in the collection.
$ db.areaMap.ensureIndex({co:'2d'})
$ db.areaMap.find({co:{$near:[12, 8]}, type:'R'}).limit(3)
$ db.areaMap.find({co:{$near:[12, 8], $maxDistance:4}, type:'R'})
Let's now go through what we did. Before we continue, let's define what exactly we mean by the distance between two points. Suppose on a cartesian plane that we have two points (x1, y1) and (x2, y2), the distance between them would be computed using the formula:
√(x1 – x2)2 + (y1 – y2)2
Suppose the two points are (2, 10) and (12, 3), the distance would be: √(2 – 12)2 + (10 – 3)2 = √(-10)2 + (7)2 = √149 =12.207.
After knowing how calculations for distance calculation are done behind the scenes by MongoDB, let's see what we did right from step 1.
We started by importing the data normally into a collection, areaMap
in the test
database and created an index as db.areaMap.ensureIndex({co:'2d'})
. The index is created on the field co
in the document and the value is a special value, 2d
, which denotes that this is a special type of index called 2D geospatial index. Usually, we give this value as 1
or -1
in other cases denoting the order of the index.
There are two types of indexes. The first is a 2D index that is commonly used for planes whose span is less and do not involve spherical surfaces. It could be something like a map of the building, a locality, or even a small city where the curvature of the earth covering the portion of the land is not really significant. However, once the span of the map increases and covers the globe, 2D indexes will be inaccurate for predicting the values as the curvature of the earth needs to be considered in the calculations. In such cases, we go for spherical indexes, which we will discuss soon.
Once the 2D index is created, we can use it to query the collection and find some points near the point queried. Execute the following query:
> db.areaMap.find({co:{$near:[12, 8]}, type:'R'}).limit(3)
It will query for documents that are of the type R, which are of type restaurants
and closes to the co-ordinates (12,8). The results returned by this query will be in the increasing order of the distance from the point in question, (12, 8) in this case. The limit just limits the result to top three documents. We may also provide the $maxDistance
in the query, which will restrict the results with a distance less than or equal to the provided value. We queried for locations not more than four units away, as follows:
> db.areaMap.find({co:{$near:[12, 8], $maxDistance:4}, type:'R'})