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, called 2D indexes, is the simpler of the two. It assumes that the data is given as x,y coordinates. The second one. called 3D or spherical indexes, is relatively more complicated. In this recipe, we will explore 2D indexes and execute some queries on 2D data. The data on which we are going to work is a 25 X 25 grid with some coordinates representing bus stops, restaurants, hospitals, and gardens.
Refer to the Connecting to a single node from a Java client recipe from Chapter 1, Installing and Starting the MongoDB Server, for all the necessary setup for this recipe. Download the data file named 2dMapLegacyData.json
and keep it ready to import on the local filesystem. Open a Mongo shell connecting to the local MongoDB instance.
2dMapLegacyData.json
file 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 us now go through what we did. Before we continue, let us define what exactly we mean by the distance between two points. Suppose on a cartesian plane we have two points, (x1, y1) and (x2, y2), the distance between them would be computed using the following formula:
For example, suppose the two points are (2, 10) and (12, 3), the distance would be as follows:
After knowing how calculations for distance are done behind the scenes by MongoDB, let us see what we did right from step 1.
We started by importing the data normally into a areaMap
collection in the x database and created an index as db.areaMap.ensureIndex({co:'2d'})
. The index is created on the co
field 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: 2D index and spherical index. A 2D index is commonly used for planes whose span is less and does not involve spherical surfaces. It could be something such as 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, as follows:
> db.areaMap.find({co:{$near:[12, 8]}, type:'R'}).limit(3)
We will query for documents that are of type R, that is, those documents for "restaurants" and that are closest to the point (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 the top three documents. We may also provide $maxDistance
in the query, which will restrict the results to 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'})