This content originally appeared on DEV Community and was authored by Akash Shyam
Dealing with coordinates can be a huge pain, so why not take the easy way? Instead of wrestling with coordinates in the frontend, push it away to the backend and let mongoDB do the work. Today, we'll look at dealing with geospatial data in mongoDB or mongoose. First on our list is GeoJSON.
GeoJSON
It has various data types to make dealing with coordinates easy. Keep in mind that longitude comes before latitude:
1) Point
The simplest of all types, it's basically a coordinate i.e. a longitude and a latitude:
// A point
{ type: "Point", coordinates: [ 40, 5 ] }
2) LineString
It's an array of array of coordinates, which will be joined to form a line. It basically consists of an array of points.
// A linestring
{ type: "LineString", coordinates: [ [ 40, 5 ], [ 41, 6 ] ] }
3) Polygon
It's a polygon, that's it! squares, rectangles, hexagons, decagons, quadrilaterals so on. This must be a closed figure(the first point must be the same as the last point, I'm sounding like my maths teacher now ?).
We draw the sides of the polygon using linestrings. Now, to illustrate this better, I'm going to draw a very very simple coordinate grid(don't worry, nothing complicated).
(I apologize on behalf of my bad designing skills for that crude grid)
Now, let's draw a simple polygon:
Here's how we can represent this in code:
{
type : "Polygon",
coordinates : [
[ [ 1 , 2 ] , [ 4 , 4 ] , [ 6 , 3 ] , [ 5 , 1 ], [1, 2] ],
]
}
There are a few to notice in this:
The nested arrays go 3 levels deep, I'll get back to this in a minute
In the diagram, there are only 4 points but we have written 5 points in our code. This is because the first point and last point overlap in the diagram so it's not visible. To make this a closed figure and a valid
Polygon
, we need to specify the last value the same as the first value to tell mongoDB that the figure has ended.
As I promised earlier, I'm going to explain the secret of the nested arrays:
The first array holds all the rings(I'll explain this in a second).
The second one holds each ring. Now, what are rings? It's basically a hole inside the polygon. So, the figure holds the area between the polygons. Here's a diagram:
The white triangle inside is a ring
. The figure contains the area inside the outer polygon but outside the white area( the area shaded in red is contained).
- Finally, the 3rd array is our old friend, the array of coordinates.
The code for this polygon would look like this:
{
type : "Polygon",
coordinates : [
[ [ 1 , 2 ] , [ 4 , 4 ] , [ 6 , 3 ] , [ 5 , 1 ], [1, 2] ],
[ [ 3 , 2 ] , [ 5 , 3 ] , [ 4 , 2 ] , [ 3 , 2 ] ],
]
}
That was a long (and hopefully not boring) maths lesson. Let's actually play around with these types and learn about more operators.
$geometry
It holds our geometrical data type (eg: Point
, Polygon
) and is used in tandem with other operators.
{
$geometry: {
type : "Polygon",
coordinates : [
[ [ 1 , 2 ] , [ 4 , 4 ] , [ 6 , 3 ] , [ 5 , 1 ], [1, 2]
]
}
}
$geoIntersects
It checks if the coordinates in a document are intersecting(not necessarily completely inside) the provided geometrical type(It has to be a 2d type i.e. Polygon
).
Places.find(
{
location: {
$geoIntersects: {
$geometry: {
type : "Polygon",
coordinates : [
[
[ 1 , 2 ] , [ 4 , 4 ] , [ 6 , 3 ] , [ 5 , 1 ], [1, 2]
]
]
}
}
}
}
)
$geoWithin
Checks if the coordinates in a document are completely inside the provided Polygon
(single/multi ringed).
Places.find(
{
location: {
$geoWithin: {
$geometry: {
type : "Polygon",
coordinates : [
[
[ 1 , 2 ] , [ 4 , 4 ] , [ 6 , 3 ] , [ 5 , 1 ], [1, 2]
]
]
}
}
}
}
)
If you want to do the same thing, but in a circle(i.e. in a particular radius from the coordinates) we use $center
. It takes in an array which has two elements. The first is the coordinates for the center and the second is the radius. The format is [[coordinateX, coordinateY], radius]
Places.find(
{
location: { $geoWithin: { $center: [ [-74, 40.74], 10 ] }
}
);
$near
Fetches all documents which are have a certain distance from a specified coordinate which can be controlled using minimum and maximum lengths. Also, it will sort the documents from nearest to farthest.
Places.find(
{
location:
{ $near :
{
$geometry: {
type: "Point",
coordinates: [ -68, 35 ]
},
}
}
}
)
We can optionally specify a $minDistance
and $maxDistance
.
Places.find(
{
location:
{ $near :
{
$geometry: {
type: "Point",
coordinates: [ -68, 35 ],
$minDistance: 500,
$maxDistance: 2000
},
}
}
}
)
Conclusion
You might be thinking, how is this useful? Well,
Suppose our user is looking for restaurants near him, we can provide all restaurants in a 10 mile radius.
Thanks for reading until here. If you liked the article and learn something today, don't forget to leave a like and follow me on dev.to!
This content originally appeared on DEV Community and was authored by Akash Shyam
Akash Shyam | Sciencx (2021-05-07T10:28:43+00:00) An Immersive Guide to Geospatial MongoDB Data. Retrieved from https://www.scien.cx/2021/05/07/an-immersive-guide-to-geospatial-mongodb-data/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.