Mongod (MongoDB server) and mongosh (MongoDB shell) installed on your system.
Familiarity with the basics of mongosh.
In real-world applications we often need to implement geospatial (also called location-based) queries, such as finding restaurants near you, finding the distance between two locations, and more.
MongoDB provides the functionality to store locations under the object type geoJSON and their coordinates against the coordinate field in [longitude, latitude] form where longitude must lie between [-180, 180] and latitude must lie between [-90,90], both inclusive.
Before we move forward to implementation, let’s discuss geoJSON types that are provided by MongoDB.
Represents a single location point, declared as below,
{ type: "Point", coordinates: [ 27, 67 ] }
The LineString coordinates field is an array of two or more points that represent a path in the real world.
It is declared as-
{ type: "LineString", coordinates: [ [ 27, 67 ], [ 52, 4 ] ] }
The Polygon coordinates field is an array of linear rings. Linear rings have at least four coordinates, and the first coordinate is the same as the last, making a loop. Learn more about linear rings here.
Polygon coordinates may contain a single linear ring or multiple rings.
In the case of a single ring, polygon can be declared as,
1
2
3
4
{
type: "Polygon",
coordinates: [[[2, 1], [3, 4], [5, 1], [2, 1]]]
}
Note: in polygons with a single ring, the ring can’t self intersect.
In the case of multiple rings:
The first ring is the outer ring,
Interior rings are completely contained by the outer ring,
Interior rings do not overlap, intersect, or share edges,
No ring self intersects.
Declaration is given as,
1
2
3
4
5
6
7
{
type: "Polygon",
coordinates: [
[[0.01, 0.02], [7.01, 1.03], [3.01, 5.1], [0.01, 0.02]],
[[2.0, 1.01], [4.0, 2.0], [3.02, 3.0], [2.0, 1.01]]
]
}
Which, in actual representation, looks like,
In LineString coordinates the field is an array of points.It is defined as,
1
2
3
4
5
6
7
8
{
type: "MultiPoint",
coordinates: [
[162.07985, 20.66911],
[126.73567, -21.59424],
[-57.94873, 0.03998]
]
}
In MultiLineString, the coordinates field is array of linestrings,
1
2
3
4
5
6
7
8
{
type: "MultiLineString",
coordinates: [
[[162.07985, 20.66911], [163.07945, 21.56721]],
[[126.73567, -21.59424], [127.74537, -22.54623]],
[[-57.94873, 0.03998], [-58.73823, 1.12934]]
]
}
In MultiPolygon, the coordinates field is array of polygons,
1
2
3
4
5
6
7
{
type: "MultiPolygon",
coordinates: [
[[[0.01, 0.02], [7.01, 1.03], [3.01, 5.1], [0.01, 0.02]]],
[[[2.2, 1.01], [4.02, 2.01], [3.2, 3], [2.2, 1.01]]]
]
}
It is a complex geoJSON object that is used to store the above-mentioned geometries under one variable. It is defined as,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
type: "GeometryCollection",
geometries: [
{
type: "MultiPoint",
coordinates: [
[162.07985, 20.66911],
[126.73567, -21.59424],
[-57.94873, 0.03998]
]
},
{
type: "MultiLineString",
coordinates: [
[[162.07985, 20.66911], [163.07945, 21.56721]],
[[126.73567, -21.59424], [127.74537, -22.54623]],
[[-57.94873, 0.03998], [-58.73823, 1.12934]]
]
},
{
type: "MultiPolygon",
coordinates: [
[[[0.01, 0.02], [7.01, 1.03], [3.01, 5.1], [0.01, 0.02]]],
[[[2.0, 1.01], [4.0, 2.0], [3.02, 3.0], [2.0, 1.01]]]
]
}
]
}
In MongoDB we need to create geospatial indexes to perform geospatial queries as we do in text search.
There are two types of indexes for geospatial search.
The 2d index is used when we are performing calculations on two-dimensional geometrical planes. We will not discuss these in detail in this article. A 2d index can be created by running
db.collection.createIndex( { <location field> : "2d" } )
Where location_field whose value is in legacy coordinates ([x,y] instead of [long,lat])
A 2dsphere index is used when performing queries/calculation on earth-like spheres.
It can be created as,db.collection.createIndex( { <location_field> : "2dsphere" } )
Here, location field can be of type geoJSON object or legacy coordinates.
Now, let’s implement.
Run your MongoDB server on your system by running:
In Linux terminal:$ sudo systemctl start mongod
In Windows cmd:C:\mongodb\bin\mongod.exe
Now start mongo shell (mongosh) by running:
In Linux terminal:$ mongosh
In Windows cmd:C:\mongodb\bin\mongosh.exe
Now create a new database named data by running:
use data
Since traveling is fun, we will search the data of tourist destinations given below. Here we
are inserting tourist places data in touristPlaces collection (MongoDB will create a collection if it doesn’t exist).
Enter into editor mode by running .editor in mongosh and then run the given command by pasting it to editor and then pressing ctrl+D.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
db.touristPlaces.insertMany([
{
name: "Taj Mahal",
loc: {
type: "Point",
coordinates: [78.0421, 27.1751]
}
},
{
name: "Christ the Redeemer",
loc: {
type: "Point",
coordinates: [-43.2105, -22.9519]
}
},
{
name: "Machu Pichu",
loc: {
type: "Point",
coordinates: [-72.5450, -13.1631]
}
},
{
name: "Colosseum",
loc: {
type: "Point",
coordinates: [12.4922, 41.8902]
}
},
{
name: "Petra",
loc: {
type: "Point",
coordinates: [35.4444, 30.3285]
}
},
{
name: "Chichen Itza",
loc: {
type: "Point",
coordinates: [-88.5678, 20.6843]
}
},
{
name: "Great Wall of China",
loc: {
type: "LineString",
coordinates: [
[119.88281248330487, 40.12849105218277],
[117.9492187335749, 39.99395568931138],
[116.41113279628864, 39.99395568931138],
[115.22460935894841, 40.363288336228116],
[114.30175779657665, 40.83043687292947],
[112.9394531092724, 41.19518982474543],
[111.88476560941639, 41.39329428402743],
[110.7421874845739, 41.62365538591387],
[109.37988279726065, 41.7221305803468],
[108.45703123488892, 41.787697000607125],
[107.62207029751265, 41.7221305803468],
[106.83105467261615, 41.49212083492374],
[106.08398436022638, 41.095912051657336],
[105.3808593603254, 40.73060847308376],
[104.8535156103974, 40.4970923679988],
[103.75488279804368, 40.663972871678155],
[103.31542967311114, 40.863679660759864],
[102.4804687357259, 41.19518982474543],
[101.99707029829567, 41.29431725840174],
[101.20605467339917, 41.32732631561273],
[100.63476561098241, 41.029643382432994],
[100.41503904851166, 40.863679660759864],
[98.7011718612524, 40.56389452596331],
[98.30566404880867, 40.69729900392594],
[97.86621092386717, 41.095912051657336],
[97.33886717393918, 41.39329428402743],
[96.54785154905167, 41.787697000607125],
[95.62499998667992, 41.85319643297941],
[94.13085936189141, 41.82045509135492],
[93.38378904949266, 41.82045509135492],
[93.38378904949266, 41.85319643297941]
]
}
}
])
You will receive output as:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
{ ...acknowledged: true, ...insertedIds: { ..... '0': ObjectId("61584ae1cf5e2c63db337c32"), ..... '1': ObjectId("61584ae1cf5e2c63db337c33"), ..... '2': ObjectId("61584ae1cf5e2c63db337c34"), ..... '3': ObjectId("61584ae1cf5e2c63db337c35"), ..... '4': ObjectId("61584ae1cf5e2c63db337c36"), ..... '5': ObjectId("61584ae1cf5e2c63db337c37"), ..... '6': ObjectId("61584ae1cf5e2c63db337c38") ..... } ... }
The above shows insertion completed successfully.
Now to perform a search we need to create the 2dsphere index, which we can do by running the below command in mongosh.db.touristPlaces.createIndex( { loc: "2dsphere" } )
Now suppose we are currently in Delhi, India (lat:28.644800, long:77.216721) and we want to travel to the nearest tourist place within a range of 1,000,000 meters or 1,000 km. We can perform our search using $near attribute as,
1
2
3
4
5
6
7
8
9
10
11
12
db.touristPlaces.find({
loc: {
$near: {
$geometry: {
type: "Point",
coordinates: [77.216721, 28.644800]
},
$minDistance: 0,
$maxDistance: 1000000
}
}
})
And we will get output as,
1
2
3
4
5
6
7
8
9
10
[
{
_id: ObjectId("61584ae1cf5e2c63db337c32"),
name: 'Taj Mahal',
loc: {
type: 'Point',
coordinates: [78.0421, 27.1751]
}
}
]
Now increase the range to 10,000km = 10,000,000 meters, and repeat the above query.
We get the result below,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
[
{
_id: ObjectId("61584ae1cf5e2c63db337c32"),
name: 'Taj Mahal',
loc: {
type: 'Point',
coordinates: [78.0421, 27.1751]
}
},
{
_id: ObjectId("61584ae1cf5e2c63db337c38"),
name: 'Great Wall of China',
loc: {
type: 'LineString',
coordinates: [
[119.88281248330487, 40.12849105218277],
[117.9492187335749, 39.99395568931138],
[116.41113279628864, 39.99395568931138],
[115.22460935894841, 40.363288336228116],
[114.30175779657665, 40.83043687292947],
[112.9394531092724, 41.19518982474543],
[111.88476560941639, 41.39329428402743],
[110.7421874845739, 41.62365538591387],
[109.37988279726065, 41.7221305803468],
[108.45703123488892, 41.787697000607125],
[107.62207029751265, 41.7221305803468],
[106.83105467261615, 41.49212083492374],
[106.08398436022638, 41.095912051657336],
[105.3808593603254, 40.73060847308376],
[104.8535156103974, 40.4970923679988],
[103.75488279804368, 40.663972871678155],
[103.31542967311114, 40.863679660759864],
[102.4804687357259, 41.19518982474543],
[101.99707029829567, 41.29431725840174],
[101.20605467339917, 41.32732631561273],
[100.63476561098241, 41.029643382432994],
[100.41503904851166, 40.863679660759864],
[98.7011718612524, 40.56389452596331],
[98.30566404880867, 40.69729900392594],
[97.86621092386717, 41.095912051657336],
[97.33886717393918, 41.39329428402743],
[96.54785154905167, 41.787697000607125],
[95.62499998667992, 41.85319643297941],
[94.13085936189141, 41.82045509135492],
[93.38378904949266, 41.82045509135492],
[93.38378904949266, 41.85319643297941]
]
}
},
{
_id: ObjectId("61584ae1cf5e2c63db337c36"),
name: 'Petra',
loc: {
type: 'Point',
coordinates: [35.4444, 30.3285]
}
},
{
_id: ObjectId("61584ae1cf5e2c63db337c35"),
name: 'Colosseum',
loc: {
type: 'Point',
coordinates: [12.4922, 41.8902]
}
},
{
_id: ObjectId("61584ae1cf5e2c63db337c33"),
name: 'Christ the Redeemer',
loc: {
type: 'Point',
coordinates: [-43.2105, -22.9519]
}
},
{
_id: ObjectId("61584ae1cf5e2c63db337c37"),
name: 'Chichen Itza',
loc: {
type: 'Point',
coordinates: [-88.5678, 20.6843]
}
},
{
_id: ObjectId("61584ae1cf5e2c63db337c34"),
name: 'Machu Pichu',
loc: {
type: 'Point',
coordinates: [-72.545, -13.1631]
}
}
]
Notice that all results are sorted on the basis of distance from the given coordinates of Delhi, India (at:28.644800, long:77.216721).
Now you can search places easily, you won’t get lost.