Geospatial Commands

Make your data beautiful again.

Geospatial Tagging

Any document or object in monsterDB can be tagged or appended with a geospatial point, this point is an arbitrary position in a 2 dimensional space ie x,y. The general way to do this is using a Point object within the document in this format:

{ type: "Point", coordinates: [ x, y ] }

Any document object in the database can have one or many properties that are Points:

 { Name: "Robert", 
    age: "Born Yesterday", 
    birthLocation: { type: "Point", coordinates: [ 40.1, 5.0 ] }, 
    currentLocation: { type: "Point", coordinates: [ 40.0, 5.1] } 
 }

Indexing Points

usage from CLI: 
  db.collectionName.createIndex({fieldName: "2d"}, {name: "indexName", accuracy: bits})

First document parameter will bind an index to the field name shown as a 2d index (geo hashed).

Second parameter is the optional configuration of the 2d indexing, fields are as follows:

name: optional name of the index

accuracy: number of bits to use for the 2d geo hash, the lower the number will result in the points being indexed in larger buckets, the larger the number, the smaller buckets. As such an element of trial and error is needed to index for your purpose, but the more data in the collection the accuracy should probably raise to reduce the amount of time monsterDB has to scan through the index to find true hits.

Geo Hashing is basically a 2 dimensional grid system every document will fall into 1 square only, thus this has some disadvantages in the sense that often a point will appear on the edge of the grid between two squares. Currently the implementation will rely on you deciding the size of the squares using the accuracy parameter. For example if you find that the default 12 bits is too granular and some points are not being found, you should try using 11 bits.

GeoWithin

To facilitate the retrieval of document objects using the index or even without an index, there are several search mechanisms you can use, but all of them have to be encased as a geoWithin statement:

{fieldName: {$geoWithin: { selector }}

fieldName is the name of the property in your document/index 

selector is one of the following:

Selectors

Point: Searches for documents at exactly the same point, with a minimal margin for error.

{ type: "Point", coordinates: [ x, y ] }

Line: searches for points that intersects exactly on the defined line:

{ type: "Line", coordinates: [ [ x1, y1 ], [ x2, y2 ] ] }

LineString: similar to line, but line can have corners, as an example three points on a line string is a line with a corner would at the second point.

{ type: "LineString", coordinates: [ [ x1,y1 ], [ x2,y2 ], [ x3, y3 ] ] }

Polygon: Complex but useful selector that allows you to define a unlimited number of points the last point always being the same as the first (if not we add it). And the documents within that geo space will be selected.

{type: "Polygon", coordinates: [ [ [ x0, y0 ] , [ x1, x1 ] , [ xn, yn ] , [ x0, y0  ] ] ] }

Center: searches for points within the area defined by the radius from the center point x,y. 

{ $center: [ [ x , y ], r ] }}

 

 

Usage examples:

For a given set of documents:

{"FirstName":"Bob","LastName":"Smith","location":{"type":"Point","coordinates":[41,6]}}

 

{“FirstName”:”Robert”,”LastName”:”Smite”,”location”:{“type”:”Point”,”coordinates”:[31,6]}}

{“FirstName”:”Robert”,”LastName”:”Haynes”,”location”:{“type”:”Point”,”coordinates”:[40,5]}}

{“FirstName”:”Bob”,”LastName”:”Haynes”,”location”:{“type”:”Point”,”coordinates”:[30,5]}}

The following statements:

Point:

{location: {$geoWithin: { type: "Point", coordinates: [ 30, 5 ] } }}

results in

{"FirstName":"Bob","LastName":"Haynes","location":{"type":"Point","coordinates":[30,5]}

Line:

{location: {$geoWithin: { type: "Line", coordinates: [ [ 39, 4 ], [ 42, 7 ] ] } }}

results in

{"FirstName":"Bob","LastName":"Smith","location":{"type":"Point","coordinates":[41,6]},"_id":"af6a7256-8b06-424a-9b76-c8efcb843a0f"}

 

{“FirstName”:”Robert”,”LastName”:”Haynes”,”location”:{“type”:”Point”,”coordinates”:[40,5]},”_id”:”2d127a2f-f462-4c94-9947-22c054dc1a74″}

LineString

{location: {$geoWithin: { type: "LineString", coordinates: [ [ 39, 4 ], [ 42, 7 ], [ 30, 5 ] ] } }}

results in

{"FirstName":"Bob","LastName":"Smith","location":{"type":"Point","coordinates":[41,6]},"_id":"af6a7256-8b06-424a-9b76-c8efcb843a0f"}

 

{“FirstName”:”Robert”,”LastName”:”Haynes”,”location”:{“type”:”Point”,”coordinates”:[40,5]},”_id”:”2d127a2f-f462-4c94-9947-22c054dc1a74″}

{“FirstName”:”Bob”,”LastName”:”Haynes”,”location”:{“type”:”Point”,”coordinates”:[30,5]},”_id”:”02e7d220-a3c0-464f-a01b-af861d12b4d4″}

Polygon

{location: {$geoWithin: {type: "Polygon", coordinates: [ [ [ 30 , 5 ] , [ 31 , 5 ] , [ 31 , 6 ] , [ 30 ,  6 ], [ 30 ,  5 ] ] ] } }}

results in

{"FirstName":"Robert","LastName":"Smite","location":{"type":"Point","coordinates":[31,6]},"_id":"90286ec2-da55-41ee-ac43-ca5cdbe15d9d"}

 

{“FirstName”:”Bob”,”LastName”:”Haynes”,”location”:{“type”:”Point”,”coordinates”:[30,5]},”_id”:”02e7d220-a3c0-464f-a01b-af861d12b4d4″}

$center:

{location: {$geoWithin: {$center: [ [ 30 , 5 ], 5 ] }}}

results in

{"FirstName":"Robert","LastName":"Smite","location":{"type":"Point","coordinates":[31,6]},"_id":"90286ec2-da55-41ee-ac43-ca5cdbe15d9d"}

 

{“FirstName”:”Bob”,”LastName”:”Haynes”,”location”:{“type”:”Point”,”coordinates”:[30,5]},”_id”:”02e7d220-a3c0-464f-a01b-af861d12b4d4″}

Fork me on GitHub