diff --git a/draft/applications/geospatial-indexes.txt b/draft/applications/geospatial-indexes.txt index c23d31f2c7b..24322613552 100644 --- a/draft/applications/geospatial-indexes.txt +++ b/draft/applications/geospatial-indexes.txt @@ -1,175 +1,159 @@ ===================== -Using Geospatial Data +Query Geospatial Data ===================== .. default-domain:: mongodb -MongoDB provides functionality to store and query geospatial data with -specialized operators. This document introduces geospatial data -modeling, indexing operations, and provides example queries using the -:ref:`geospatial query operators `. For -more information about geospatial indexes and operations see the -:doc:`/core/geospatial-indexes` document. +Geospatial data stores location values for documents that can be used to +query documents based on geographic location, such as city, region, or +address. For an introduction to geospatial data, see +:doc:`/core/geospatial-indexes`. -.. _geospatial-coordinates: +You can query geospatial data using the following approaches: -.. This include inserts an introduction to geospatial modeling. - "Representing Coordinate Data" -.. include:: /includes/geospatial-coordinates.rst +- Proximity queries, which query based on distance to a given point. See + :ref:`geospatial-indexes-proximity`. -.. index:: geospatial queries -.. _geospatial-queries: -.. _geospatial-querying: - -Queries -------- - -There are two operators to query geospatial data in MongoDB, -the general :method:`find() ` method and the -specialized :dbcommand:`geoNear` command. - -You may query geospatial data using the :method:`find() -`, this is the same as querying other types of -data in MongoDB. Another way is to use the :dbcommand:`geoNear` -command, this is the same as running database commands. - -The :dbcommand:`geoNear` command is more specialized as it returns -detailed geospatial information for each result such as distance and -overall query performance. This provides additional benefits when only -working with geospatial data. +- Bounded queries, which return documents within a defined area. Bounded + queries do not sort results and are faster than proximity queries. See + :ref:`geospatial-indexes-bounded`. -.. TODO does it make sense to have this here?? +- Query for exact matches using the :method:`find() + `. Exact geospatial queries have applicability + for a limited selection of cases. See + :ref:`geospatial-indexes-exact-match`. -.. note:: +.. index:: geospatial queries; proximity +.. _geospatial-indexes-near: +.. _geospatial-indexes-proximity: - By default, MongoDB calculates distances using flat geometry. +Proximity Queries +----------------- - MongoDB can also calculate distances based on :ref:`spherical - geometry ` by using - :ref:`spherical query operators `. +Proximity queries find the first "N" documents closest to a point. To +perform proximity queries you use either the :method:`find() +` method with the :operator:`$near` operator or +you use the :dbcommand:`geoNear` command. -.. index:: geospatial queries; exact +The :method:`find() ` method with the +:operator:`$near` operator returns 100 documents by default and sorts +the results by distance. The :operator:`$near` operator uses the +following form: -.. _geospatial-query-exact: +.. code-block:: javascript -Exact -~~~~~ + db.collection.find( { : { $near: [ x, y ] } } ) -You can use the :method:`find() ` method to query -for an exact match on a location. These queries have the prototypical -form: +.. example:: -.. code-block:: javascript + The following query - db.collection.find( { : [ x, y ] } ) + .. code-block:: javascript -This query will return any documents with the value of ``[ x, y ]``. + db.places.find( { loc: {$near: [-70,40] } }) -Exact geospatial queries have applicability for a limited selection of -cases, the :ref:`proximity ` method and :ref:`bounded -` method provide more useful results. + returns output similar to the following: -.. index:: geospatial queries; proximity -.. _geospatial-query-near: -.. _geospatial-query-proximity: + .. code-block:: javascript -Proximity -~~~~~~~~~ + { "_id" : ObjectId(" ... "), "loc" : [ -73, 40 ] } -To find all documents that are within a proximity of a point, use the -:operator:`$near` operator with the :method:`find() -` method. By default, the :operator:`$near` will -return 100 points sorted by distance. +The :dbcommand:`geoNear` command provides more information than does the +:operator:`$near` operator but does not sort results. The +:dbcommand:`geoNear` command also offers additional operators, such as +operators to query for :ref:`maximum ` or +:ref:`spherical ` distance. For a list of +operators, see :dbcommand:`geoNear`. -The prototype form for the :operator:`$near` operator is: +Without additional operators, the :dbcommand:`geoNear` command uses the +following form: .. code-block:: javascript - db.collection.find( { : { $near: [ x, y ] } } ) + db.runCommand( {geoNear: "[collection]", near: [ x, y ] } ) -For example, +.. example:: -.. code-block:: javascript + The following command returns the same results as the + :operator:`near` in the previous example but with more information: - db.places.find( { loc: {$near: [-70,40] } }) + .. code-block:: javascript -and the output is: + db.runCommand( {geoNear: "places", near: [ -74, 40.74 ] } ) -.. code-block:: javascript + The output is: - { "_id" : ObjectId(" ... "), "loc" : [ -73, 40 ] } + .. code-block:: javascript -The :dbcommand:`geoNear` command provides the equivalent functionality -to the :operator:`$near` operator but does not sort the results, -returns more information for each document found, and provides -additional operators. + { + "ns" : "test.places", + "near" : "0110000111111000000111111000000111111000000111111000", + "results" : [ + { + "dis" : 3, + "obj" : { + "_id" : ObjectId(" ... "), + "loc" : [ + -73, + 40 + ] + } + } + ], + "stats" : { + "time" : 2, + "btreelocs" : 0, + "nscanned" : 1, + "objectsLoaded" : 1, + "avgDistance" : 3, + "maxDistance" : 3.0000188685220253 + }, + "ok" : 1 + } -In its most simple form, the :dbcommand:`geoNear` command has the -following prototypical form: +.. index:: geospatial queries; distance limit +.. _geospatial-indexes-distance: -.. code-block:: javascript +Distance Queries +~~~~~~~~~~~~~~~~ - db.runCommand( {geoNear: "[collection]", near: [ x, y ] } ) +You can limit a proximity query to those documents that fall within a +maximum distance of a point. You specify the maximum distance using the +units specified by the coordinate system. For example, if the coordinate +system uses meters, you specify maximum distance in meters. -The following command returns the same results as the :operator:`near` -in the previous example: +To specify distance using the :method:`find() ` +method, use :operator:`$maxDistance` operator. Use the following form: .. code-block:: javascript - db.runCommand( {geoNear: "places", near: [ -74, 40.74 ] } ) + db.collection.find( { : { $near: [ x, y ] } , $maxDistance : z } ) -and the output is: +To specify distance with the :dbcommand:`geoNear` command, use the +``maxDistance`` option. Use the following form: .. code-block:: javascript - { - "ns" : "test.places", - "near" : "0110000111111000000111111000000111111000000111111000", - "results" : [ - { - "dis" : 3, - "obj" : { - "_id" : ObjectId(" ... "), - "loc" : [ - -73, - 40 - ] - } - } - ], - "stats" : { - "time" : 2, - "btreelocs" : 0, - "nscanned" : 1, - "objectsLoaded" : 1, - "avgDistance" : 3, - "maxDistance" : 3.0000188685220253 - }, - "ok" : 1 - } - - -.. seealso:: + db.runCommand( { geoNear: "collection", near: [ x, y ], maxDistance: z } ) - :ref:`geospatial-query-exact` +.. _geospatial-indexes-limit: -.. _geospatial-query-limit: +Limit the Number of Results +~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Limit -````` -The :method:`limit() ` method can be used with -:method:`find() ` to limit the number of results. By default, geospatial queries with the :method:`find() -` method return 100 documents sorted by -distance. The following is the prototype operation: +` method return 100 documents, sorted by distance. + +To limit the result when using the :method:`find() +` method, use the :method:`limit() +` method. The following is the prototype operation: .. code-block:: javascript db.collection.find( { : { $near: [ x, y ] } } ).limit(n) -To limit the result set using the :dbcommand:`geoNear` command, use -the ``num`` option to limit results. The following is a prototype of -the command: +To limit the result set when using the :dbcommand:`geoNear` command, use +the ``num`` option. The following is a prototype of the command: .. code-block:: javascript @@ -178,7 +162,7 @@ the command: The :method:`limit() ` method and ``near`` parameter do not limit geospatial query results by distance, only the number of results. To limit geospatial search results by distance, please see -the :ref:`geospatial-query-distance` section. +the :ref:`geospatial-indexes-distance` section. .. note:: @@ -193,55 +177,25 @@ the :ref:`geospatial-query-distance` section. ``num`` option will only return the specified number of unsorted documents. -.. TODO double check with greg... - -.. index:: geospatial queries; distance limit - -.. _geospatial-query-distance: - -Distance -```````` - -To query geospatial data by distance, use the :operator:`$maxDistance` -operator with :method:`find() `, the function -prototype is: - -.. code-block:: javascript - - db.collection.find( { : { $near: [ x, y ] } , $maxDistance : z } ) - -The equivalent :dbcommand:`geoNear` option is ``maxDistance``, the -prototype is: - -.. code-block:: javascript - - db.runCommand( { geoNear: "collection", near: [ x, y ], maxDistance: z } ) - -Specify the distance in the ``maxDistance`` option using the same units -as the coordinate system specified. For example, if the indexed -location data is in meters, the distance units are also in meters. +.. TODO double check with greg -See the :ref:`geospatial-query-limit` section to limit geospatial -query results by the number of returned :term:`documents `. +.. _geospatial-indexes-within: +.. _geospatial-indexes-bounded: -.. _geospatial-within: -.. _geospatial-query-bounded: - -Bounded -~~~~~~~ +Bounded Queries +--------------- Bounded queries return documents within a particular shape and use the -:operator:`$within` operator to specify various shapes. +:operator:`$within` operator to define the shape. -The following is a list of acceptable shapes for bounded queries using -the :operator:`$within` operator: +Bounded queries can use the following shapes: -- circles, -- rectangles, -- polygons. +- :ref:`geospatial-indexes-circles` +- :ref:`geospatial-indexes-rectangles` +- :ref:`geospatial-indexes-polygons` Bounded queries do not return sorted results and are faster than -:ref:`proximity queries ` +:ref:`geospatial-indexes-proximity`. .. TODO update $near in operator pages @@ -255,23 +209,24 @@ Bounded queries take the following prototype form: } } ) -The following sections provide examples of bounded queries using the -:operator:`$within` operator. +The following sections describe how to query based on different shapes. + +.. _geospatial-indexes-circles: Circles -``````` +~~~~~~~ -To query for documents within a circle, you must specify the center and the -radius of the circle, using the :operator:`$within` operator and the +To query for documents within a circle, you specify the center and +the radius of the circle using the :operator:`$within` operator and :operator:`$center` option. Consider the following prototype query: .. code-block:: javascript db.collection.find( { "field": { "$within": { "$center": [ center, radius ] } } } ) -The following example query will return all documents that have -coordinates that exist within the circle centered on ``[-74, 40.74]`` -with a radius of ``10``, using a geospatial index on the ``loc`` field: +The following example query returns all documents that have coordinates +that exist within the circle centered on ``[-74, 40.74]`` and with a +radius of ``10``, using a geospatial index on the ``loc`` field: .. code-block:: javascript @@ -280,169 +235,114 @@ with a radius of ``10``, using a geospatial index on the ``loc`` field: } } ) -The :operator:`$within` operator using :operator:`$center` may be -equivalent to using :operator:`$maxDistance`, but :operator:`$center` -has different performance characteristics. Queries using the -:operator:`$within` operator are not sorted, while :operator:`$near` -operator results are sorted. +The :operator:`$within` operator using :operator:`$center` is similar to +using :operator:`$maxDistance`, but :operator:`$center` has different +performance characteristics. Queries using the :operator:`$within` +operator are not sorted, while :operator:`$near` operator results are +sorted. -Boxes -````` +.. _geospatial-indexes-rectangles: -To query for documents that lie within a rectangle, you must specify only -the lower-left and upper-right corners for the :operator:`$box` option -using the :operator:`$within` operator. Consider the following -prototype query: +Rectangles +~~~~~~~~~~ + +To query for documents that lie within a rectangle, you specify the +lower-left and upper-right corners of the rectangle using the +:operator:`$within` operator and :operator:`$box` option. Consider the +following prototype query: .. code-block:: javascript db.collection.find( { "field": { "$within": { "$box": [ coordinate0, coordinate1 ] } } } ) -The following query will return all documents that have coordinates -that exist within the rectangle, where the lower-left corner is at ``[ -0, 0 ]`` and the upper-right corner is at ``[ 3, 3 ]`` using a +The following query returns all documents that have coordinates +that exist within the rectangle where the lower-left corner is at +``[ 0, 0 ]`` and the upper-right corner is at ``[ 3, 3 ]``, using a geospatial index on the ``loc`` field: .. code-block:: javascript db.places.find( { "loc": { "$within": { "$box": [ [0, 0] , [3, 3] ] } } } ) +.. _geospatial-indexes-polygons: + Polygons -```````` +~~~~~~~~ .. versionadded:: 1.9 + Support for polygon queries. -To query for documents that lie within a polygon, you must specify the -points of the polygon in an array, and use the :operator:`$polygon` -option with the :operator:`$within` operator. The last point in the -array will automatically be connected to the first point. Consider the following +To query for documents that lie within a polygon, you specify the points +of the polygon in an array, using the the :operator:`$within` operator +with the :operator:`$polygon` option. MongoDB automatically connects the +last point in the array to the first point. Consider the following prototype query: .. code-block:: javascript db.places.find({ "loc": { "$within": { "$polygon": [ points ] } } }) -The following query will return all documents that have coordinates -that exist within ``[0,0]``, ``[3,3]`` , ``[6,0]``. The following is -an example: +The following query returns all documents that have coordinates +that exist within ``[0,0]``, ``[3,3]`` , ``[6,0]``: .. code-block:: javascript db.places.find({ "loc": { "$within": { "$polygon": [0,0], [3,3], [6,0] } } } ) -See the :ref:`geospatial-query-distance` section to perform geospatial -queries for a particular distance around a certain point. - -.. _geospatial-query-spherical: - -Spherical -~~~~~~~~~ - -By default, MongoDB uses flat geometry to calculate distances between -points. MongoDB also supports distance calculations using spherical -geometry to provide accurate distances for geospatial information -based on a sphere or earth. - -To calculate distances between points using spherical geometry instead -of flat geometry use the following spherical query operators, shown -with their flat geometry equivalents: - -========================== =================== - Spherical Flat --------------------------- ------------------- -:operator:`$nearSphere` :operator:`$near` -:operator:`$centerSphere` :operator:`$center` -========================== =================== - -The equivalent :dbcommand:`geoNear` option to calculate using -spherical geometry is the ``{ spherical: true }`` option. - -.. admonition:: Spherical Queries Use Radians for Distance - - For spherical operators to function properly, you must convert - distances to radians, and convert from radians to distances units - for your application. - - To convert: - - - *distance to radians*: divide the distance by the radius of the - sphere (e.g. the Earth) in the same units as the distance - measurement. - - - *radians to distance*: multiply the rad ian measure by the radius - of the sphere (e.g. the Earth) in the units system that you want to - convert the distance to. +.. index:: geospatial queries +.. index:: geospatial queries; exact +.. _geospatial-indexes-exact-match: - The radius of the Earth is approximately ``3963.192`` miles or - ``6378.137`` kilometers. +Query for Exact Matches +----------------------- -The following query would return documents from the ``places`` -collection, within the circle described by the center ``[ -74, 40.74 ]`` -with a radius of ``100`` miles: +You can use the :method:`find() ` method to query +for an exact match on a location. These queries have the following form: .. code-block:: javascript - db.places.find( { loc: { $centerSphere: [ [ -74, 40.74 ] , - 100 / 3963.192 ] } } ) + db.collection.find( { : [ x, y ] } ) -You may also use the ``distanceMultiplier`` option to the -:dbcommand:`geoNear` to convert radians in the :program:`mongod` -process, rather than in your application code. Please see the -:ref:`distance multiplier ` section. +This query will return any documents with the value of ``[ x, y ]``. -The following spherical query, returns all documents in the collection -``places`` within ``100`` miles from the point ``[ -74, 40.74 ]``. +Exact geospatial queries have applicability for a limited selection of +cases, the :ref:`proximity ` method and +:ref:`bounded ` method provide more useful +results. -.. code-block:: javascript +.. _geospatial-indexes-spherical: - db.runCommand( { geoNear: "places", - near: [ -74, 40.74 ], - spherical: true - } ) +Calculate Distances Using Spherical Geometry +-------------------------------------------- -The output of the above command would be: +When you query location data, MongoDB by default calculates distances using flat +geometry, which models points on a flat surface. -.. code-block:: javascript +Optionally, you can calculate distances using spherical geometry, which +models points on a spherical surface (i.e. coordinates on Earth). - { - // [ ... ] - "results" : [ - { - "dis" : 0.01853688938212826, - "obj" : { - "_id" : ObjectId( ... ) - "loc" : [ - -73, - 40 - ] - } - } - ], - "stats" : { - // [ ... ] - "avgDistance" : 0.01853688938212826, - "maxDistance" : 0.01853714811400047 - }, - "ok" : 1 - } +To calculate distances using spherical geometry, use MongoDB's +spherical operators or options. You can use the: -.. warning:: +- :method:`find() ` method with the + :operator:`$nearSphere` operator. - Spherical queries that wrap around the poles or at the transition - from ``-180`` to ``180`` longitude raise an error. +- :method:`find() ` method with the + :operator:`$centerSphere`. -.. note:: +- :dbcommand:`geoNear` command with the ``{ spherical: true }`` option. + +.. seealso:: :ref:`geospatial-query-operators`. - While the default Earth-like bounds for geospatial indexes are - between ``-180`` inclusive, and ``180``, valid values for latitude - are between ``-90`` and ``90``. +For more information on differences between flat and spherical distance +calculation, see :ref:`geospatial-indexes-distance-calculation`. -.. _geospatial-distance-multiplier: +.. _geospatial-indexes-distance-multiplier: Distance Multiplier -~~~~~~~~~~~~~~~~~~~ +------------------- The ``distanceMultiplier`` option multiplies all distances returned by :dbcommand:`geoNear` command by an assigned value. @@ -458,7 +358,7 @@ Using ``distanceMultiplier`` in spherical queries allows one to use results from the :dbcommand:`geoNear` command without radian to distance conversion. The following example uses ``distanceMultiplier`` in the :dbcommand:`geoNear` command with a :ref:`spherical -` example: +` example: .. code-block:: javascript @@ -495,27 +395,20 @@ The output of the above command would be: } .. seealso:: - :ref:`Distance operator ` + :ref:`Distance operator ` -.. _geospatial-haystack-queries: +.. _geospatial-indexes-haystack-queries: Querying Haystack Indexes ------------------------- -Geospatial haystack indexes are a special index that is optimized for -a small area. To create geospatial indexes with the haystack option -and a particular ``bucketSize``, please see: :ref:`Haystack Index -` - -.. note:: - - Haystack indexes are not suited to returning the closest documents to - a particular location, as the closest documents could be far away - compared to the ``bucketSize``. +Haystack indexes are a special geospatial index that are optimized for a +small area. To create geospatial indexes see +:ref:`geospatial-indexes-haystack-index`. To query the haystack index, use the :dbcommand:`geoSearch` command. You must specify both the coordinate and other field to -:dbcommand:`geoSearch`, which take the following prototypical form: +:dbcommand:`geoSearch`, which take the following form: .. code-block:: javascript @@ -533,87 +426,14 @@ the ``type`` field near the example point, the command would resemble: .. note:: - :ref:`Spherical queries ` are + Haystack indexes are not suited to returning the closest documents to + a particular location, as the closest documents could be far away + compared to the ``bucketSize``. + +.. note:: + + :ref:`Spherical queries ` are not currently supported by haystack indexes. The :method:`find() ` method and :dbcommand:`geoNear` command cannot access the haystack index. - -.. _geospatial-multi-location: - -Multi-location Documents ------------------------- - -.. versionadded:: 2.0 - Support for multiple locations in a document. - -In general, MongoDB cannot support more than one set of coordinates in -a document; however, using :ref:`multi-key indexes `, -you *can* index multiple coordinates in a single document. In the -simplest example, you may have a field (e.g. ``locs``) that holds an -array of geospatial coordinates, as in the following prototype data -model: - -.. code-block:: javascript - - { - "_id": ObjectId(...), - "locs": [ - [ 55.5, 42.3 ], - [ -74, 44.74 ], - { "lat": 55.3, "long": 40.2 } - ] - } - -The values of the array may either be arrays holding coordinates, as -in ``[ 55.5, 42.3 ]`` or embedded documents as in ``{ "lat": 55.3, -"long": 40.2 }``. - -You could then create a geospatial index on the ``locs`` field, as in -the following example: - -.. code-block:: javascript - - db.places.ensureIndex( { "locs": "2d" } ) - -You may also model the location data as a field inside of a -sub-document. In this case, the document would contain field -(e.g. ``addresses``) that held an array of documents where each -document has a field (e.g. ``loc:``) that holds location -coordinates. Consider the following prototype data model: - -.. code-block:: javascript - - { - "_id": ObjectId(...), - "name": "...", - "addresses": [ - { - "context": "home", - "loc": [ 55.5, 42.3 ] - }, - { - "context": "home", - "loc": [ -74, 44.74 ] - } - ] - } - -Then, create the geospatial index on the ``addresses.loc`` field as -in the following example: - -.. code-block:: javascript - - db.records.ensureIndex( { "addresses.loc": "2d" } ) - -For documents with multiple locations, results may have the same -document many times because of multiple matches. - -To include the location field with the distance field in -multi-location document queries, specify ``includeLocs: true`` -in the :dbcommand:`geoNear` command. - -.. the following is a section about the limitations of geospatial - indexes in sharding: - -.. includes:: /includes/geospatial-sharding.rst diff --git a/draft/core/geospatial-indexes.txt b/draft/core/geospatial-indexes.txt index 66c11ea11e4..39dfd785db5 100644 --- a/draft/core/geospatial-indexes.txt +++ b/draft/core/geospatial-indexes.txt @@ -7,99 +7,112 @@ Geospatial Indexes Overview -------- -MongoDB supports location-based queries and geospatial data with a -special index. The geospatial index stores :ref:`geohashes -`, and makes it possible to query documents -based on proximity or within a bounded region. MongoDB can -calculate distances using flat or spherical geometry models. -Additionally, geospatial haystack indexes provide additional -support for specific data distribution. +Geospatial indexes makes it possible to query documents based on +geographic location. You can store two-dimensional location coordinates +in your documents and then, by creating geospatial indexes, query based +on that criteria. For example, you can query based on proximity to +another location or based on inclusion in a specified region. -This document introduces the core concepts that underpin geospatial -indexes in MongoDB. For more information, -:doc:`/applications/geospatial-indexes` provide complete documentation -of all location-based operations and queries. +You can query on both location and a second field. For example, you +might write a query to find restaurants a specific distance from a hotel +or to find museums found within a certain defined neighborhood. -.. include:: /includes/geospatial-coordinates.rst +This document describes how to include location data in your documents +and how to create geospatial indexes. For information on querying +geospatial indexes, see :doc:`/applications/geospatial-indexes`. -.. _geospatial-indexes: +.. _geospatial-indexes-coordinates: -Geospatial Indexes ------------------- +Store Location Data +------------------- + +To use geospatial indexes, you must model location data on a +pre-determined two-dimensional coordinate system, such as longitude and +latitude. You store location data as two-dimensional coordinates in a +field that holds either a two-dimensional array or an embedded document. +Consider the following two examples: + +.. code-block:: javascript + + loc : [ x, y ] + + loc : { x: 1, y: 2 } + +All your documents must store their location values in the same order. +If you use latitude and longitude as your coordinate system, always +store longitude first. MongoDB's :ref:`geospatial-indexes-spherical` only +recognize ``[ longitude, latitude ]`` ordering. + +.. _geospatial-indexes_create: + +Create a Geospatial Index +------------------------- To create a geospatial index, use the :method:`ensureIndex ` method with the value ``2d`` for the -location field of your collection. Consider the following prototype -operation: +location field of your collection. Consider the following prototype: .. code-block:: javascript db.collection.ensureIndex( { : "2d" } ) -Almost all geospatial operators will query this index for location -data. The index comprises of :term:`geohashes ` calculated -from location values and the index's geospatial :ref:`range -`. For more information on :term:`geohash`, -please refer to the :ref:`geohash ` section. +MongoDB's special :ref:`geospatial operations +` use this index when querying for location +data. -To perform queries on your geospatial data, please see -:ref:`geospatial-querying`. +When you create the index, MongoDB converts location data to binary +:term:`geohash` values, which are calculated based on both the location +data and the index's location range, as described in +:ref:`geospatial-indexes-range`. By default, the location range is is +based on longitude and latitude and is bounded by -180 inclusive and 180 +non-inclusive. You can manipulate the geohashes for increased query +precision, as described in :ref:`geospatial-indexes-precision`. -.. TODO fix this... weird duplicate reference? +MongoDB only supports *one* geospatial index per collection. -.. see:: :ref:`` for an overview on modeling - location data in MongoDB. - -.. note:: - - MongoDB only supports *one* geospatial index per - collection. Creating more than one geospatial index with a - collection will produce unexpected results. +When creating a geospatial index you can specify the options described +in this section. .. _geospatial-indexes-range: -Range -~~~~~ +Location Range +~~~~~~~~~~~~~~ + +All geospatial indexes are bounded to a location range. By default, +location range is based on longitude and latitude and is bounded by -180 +inclusive and 180 non-inclusive (i.e. ``[-180, 180)``). MongoDB returns +an error and rejects documents with coordinate data outside of the +specified range. -All geospatial indexes are bounded to a range as this range is used to -compute :term:`geohash` values. MongoDB will return an error and -reject documents with coordinate data outside of the specified range. -The default range assumes latitude and longitude data, and are between --180 inclusive and 180 non-inclusive (i.e. ``[-180, 180)``.) +MongoDB uses the location range when computing :term:`geohash` values, +as described in :ref:`geospatial-indexes-geohash`. -To configure the range of a geospatial index, use the ``min`` and -``max`` options with the :method:`ensureIndex() ` -operation, as in the following prototype: +To configure a location range other than the default, use the ``min`` +and ``max`` options with the :method:`ensureIndex() +` operation, as in the following prototype: .. code-block:: javascript db.collection.ensureIndex( { : "2d" } , { min: , max: } ) -For more information see the :ref:`geospatial precision -` and :ref:`geohash -` sections. - .. _geospatial-indexes-precision: -Precision -~~~~~~~~~ +Location Precision +~~~~~~~~~~~~~~~~~~ -Geospatial indexes consist of :term:`geohash` values and the number of -bits determine the precision of the index. More bits create more -precise :term:`geohash` values, which allow MongoDB to return more -precise results. Fewer bits create a shorter :term:`geohash` value, -which allow for faster processing. For more information on the -relationship between bits and precision, see the :ref:`geohash -` section. +The precision of location data is determined by the number of bits in +the :ref:`geospatial-indexes-geohash`. More bits create more precise location +data, which allows MongoDB to return more precise results. Fewer bits +create less precise location data but allows for faster processing. -The precision of geospatial indexes can be configured upto 32 bits. By -default, geospatial indexes use 26 bits of precision, which is precise -to roughly 2 feet or about 60 centimeters using the default range of --180 to 180. +By default, geospatial indexes use 26 bits of precision, which is +precise to roughly 2 feet or about 60 centimeters using the default +range of -180 to 180. You can configure geospatial indexes up to 32 +bits. -The precision of a geospatial index can be configured during creation by -specifying the ``bits`` option to the :method:`ensureIndex() +To configure a location precision other than the default, use the +``bits`` option in the :method:`ensureIndex() ` method, as in the following prototype: .. code-block:: javascript @@ -107,111 +120,202 @@ specifying the ``bits`` option to the :method:`ensureIndex() db.collection.ensureIndex( {: "2d"} , { bits: } ) -Only create an index with fewer than 26 bits *if* the data in your -collection is less precise and/or you're willing to sacrifice -precision for query speed. +Only create an index with fewer than 26 bits if you are willing to +sacrifice precision for query speed. -Compound Indexes -~~~~~~~~~~~~~~~~ +For more information on the relationship between bits and precision, see +:ref:`geospatial-indexes-geohash`. -:ref:`Compound indexes ` can be used with -geospatial data to improve performance that query all these fields. +Compound Geospatial Indexes +~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To create compound index with geospatial data and another field, the -prototype form is: +A geospatial index can include a second field in addition to the +location field, making the index a :ref:`index-type-compound`. This +allows for queries on the second criterion based on location. For +example, queries on carpet wholesalers in a mapped region. + +To create a geospatial index with two fields, specify the location field +first, then the second field. For example, to create a compound index on +the ``loc`` location field and on the ``product`` field (sorted in +ascending order), you would issue the following: .. code-block:: javascript - db.collection.ensureIndex( { : "2d", : 1 } ); + db.storeInfo.ensureIndex( { loc: "2d", product: 1 } ); -This index will now support regular geospatial queries as well as -queries where you must filter both by location and by another field. +This creates an index that supports queries on location alone, as well +as queries on location and ``product``. -For example, to create a compound index on the ``loc`` field and the -``type`` field, the command is: +.. _geospatial-indexes-haystack-index: + +Haystack Indexes +~~~~~~~~~~~~~~~~ + +Haystack indexes create "buckets" of documents from the same geographic +area in order to improve performance for queries limited to that area. + +Each bucket in a haystack index contains all the documents within a +specified proximity to a given longitude and latitude. You use the +``bucketSize`` parameter to determine proximity. A ``bucketSize`` of +``5`` creates an index that groups location values that are within 5 +units of the specified longitude and latitude. + +The ``bucketSize`` parameter also determines the granularity of the +index. You can tune the parameter to the distribution of your data so +that in general you search only very small regions of a two-dimensional +space. + +The areas defined by buckets can overlap, meaning a document can exist +in multiple buckets. + +Haystack indexes define location by longitude and latitude. To use +haystack indexes, your documents must also define location by longitude +and latitude. + +To build a haystack index, use the ``bucketSize`` parameter in the +:method:`ensureIndex() ` method, as in the +following prototype: .. code-block:: javascript - db.storeInfo.ensureIndex( { loc: "2d", type: 1 } ); + db.collection.ensureIndex({ : "geoHaystack", type: 1 }, + { bucketSize: }) -This will support geospatial queries as well as any query on the -``type`` field. This index can return a list of restaurants near a -given point, which can optionally filter restaurants by the ``type``, -such as "take-out," or "bar". +.. example:: -.. see also: ":ref:``" and ":ref:``" + Consider a collection with documents that contain fields similar to + the following: -.. _geospatial-haystack-index: + .. code-block:: javascript -Haystack Index -~~~~~~~~~~~~~~ + { _id : 100, { long : 126.9, lat : 35.2 }, type : "restaurant"} + { _id : 200, { long : 127.5, lat : 36.1 }, type : "restaurant"} + { _id : 300, { long : 128.0, lat : 36.7 }, type : "national park"} -Geospatial haystack indexes make it possible to tune for the -distribution of your data and build a special bucket index. Haystack -indexes improve query performance for queries limited to a specific -area. + The following command creates an index in which keys within 1 unit of + longitude or latitude are stored in the same bucket. -.. note:: + db.mydb.ensureIndex( { pos : "geoHaystack", type : 1 }, { bucketSize : 1 } ) + + The index stores the document with ``_id: 200`` in two different + buckets: in a bucket that includes ``_id: 100`` and in a separate + bucket that includes the ``_id: 300`` bucket. + +To query using a haystack index you use the +:dbcommand:`geoSearch` command. For command details, see +:ref:`geospatial-indexes-haystack-queries`. + +Haystack indexes are tuned to the bucket size and are not necessarily +suited to returning the closest documents to a particular location. + +:ref:`Spherical queries ` are not +supported by geospatial haystack indexes. + +By default, queries that use a haystack index return 50 documents. + +.. _geospatial-indexes-distance-calculation: - Haystack indexes are tuned to the ``bucketSize`` and are not suited - to returning the closest documents to a particular location, - because the closest documents could be further away than to the - ``bucketSize``. +Distance Calculation +-------------------- -The following command is the prototype to build a :term:`geoHaystack` -index: +MongoDB performs distance calculations upon the issuing of queries. By +default, MongoDB uses flat geometry to calculate distances between +points. MongoDB also supports distance calculations using spherical +geometry, to provide accurate distances for geospatial information based +on a sphere or earth. + +.. admonition:: Spherical Queries Use Radians for Distance + + For spherical operators to function properly, you must convert + distances to radians, and convert from radians to distances units + for your application. + + To convert: + + - *distance to radians*: divide the distance by the radius of the + sphere (e.g. the Earth) in the same units as the distance + measurement. + + - *radians to distance*: multiply the rad ian measure by the radius + of the sphere (e.g. the Earth) in the units system that you want to + convert the distance to. + + The radius of the Earth is approximately ``3963.192`` miles or + ``6378.137`` kilometers. + +The following query would return documents from the ``places`` +collection, within the circle described by the center ``[ -74, 40.74 ]`` +with a radius of ``100`` miles: .. code-block:: javascript - db.collection.ensureIndex({ : "geoHaystack", type: 1 }, - { bucketSize: }) + db.places.find( { loc: { $centerSphere: [ [ -74, 40.74 ] , + 100 / 3963.192 ] } } ) -The ``bucketSize`` parameter determines the granularity of the -index. A bucket value of ``5`` creates an index that stores keys -within 5 units of the coordinate in the same bucket. +You may also use the ``distanceMultiplier`` option to the +:dbcommand:`geoNear` to convert radians in the :program:`mongod` +process, rather than in your application code. Please see the +:ref:`distance multiplier ` section. -Geohaystack indexes are only queried by the :dbcommand:`geoSearch` -command, please see the :ref:`Querying Haystack Indexes -` section for command details. +The following spherical query, returns all documents in the collection +``places`` within ``100`` miles from the point ``[ -74, 40.74 ]``. -:ref:`Spherical queries ` are not -supported by geohaystack indexes. +.. code-block:: javascript -By default, all queries that use a geospatial haystack index will return 50 -documents. + db.runCommand( { geoNear: "places", + near: [ -74, 40.74 ], + spherical: true + } ) -.. _geospatial-spherical-geometry: +The output of the above command would be: -Distance Calculation Modes --------------------------- +.. code-block:: javascript -MongoDB can calculate distances using two geometry systems: flat and -spherical. The default flat geometry, which model points on a flat -surface. To use spherical geometry to calculate distances, use -spherical query operators, which model points on a spherical surface -(i.e. coordinates on Earth.) + { + // [ ... ] + "results" : [ + { + "dis" : 0.01853688938212826, + "obj" : { + "_id" : ObjectId( ... ) + "loc" : [ + -73, + 40 + ] + } + } + ], + "stats" : { + // [ ... ] + "avgDistance" : 0.01853688938212826, + "maxDistance" : 0.01853714811400047 + }, + "ok" : 1 + } + +.. warning:: + + Spherical queries that wrap around the poles or at the transition + from ``-180`` to ``180`` longitude raise an error. .. note:: - There is no difference between flat and spherical *data* as stored - in MongoDB. Rather, the only difference is the distance - formulas to calculate in flat and spherical geometry. + While the default Earth-like bounds for geospatial indexes are + between ``-180`` inclusive, and ``180``, valid values for latitude + are between ``-90`` and ``90``. -For more information on query operations for spherical geometry see the -:ref:`spherical queries ` section. +.. _geospatial-indexes-geohash: -.. _geospatial-geohash: +Geohash Values +-------------- -Geohash -------- - -To create a geospatial index, MongoDB computes the :term:`geohash` -value for coordinate pairs within the specified :term:`range +To create a geospatial index, MongoDB computes the :term:`geohash` value +for coordinate pairs within the specified :ref:`range `. To calculate a geohash value, continuously divide a 2D map into -quadrants. Then, assign each quadrant a two bit value. For example, a -two bit representation of four quadrants would be: +quadrants. Then, assign each quadrant a two-bit value. For example, a +two-bit representation of four quadrants would be: .. code-block:: javascript @@ -219,27 +323,107 @@ two bit representation of four quadrants would be: 00 10 -These two bit values, ``00``, ``01``, ``10``, and ``11``, represent -each of the quadrants, and all points within that quadrant. For a -:term:`geohash` with two bits of resolution, all points in the bottom -left quadrant would have a geohash of ``00``. The top left quadrant -would have the geohash of ``01``. The bottom right and top right would -have a geohash of ``10`` and ``11``, respectively. +These two bit values, ``00``, ``01``, ``10``, and ``11``, represent each +of the quadrants and all points within each quadrant. For a geohash with +two bits of resolution, all points in the bottom left quadrant would +have a geohash of ``00``. The top left quadrant would have the geohash +of ``01``. The bottom right and top right would have a geohash of ``10`` +and ``11``, respectively. To provide additional precision, continue dividing each quadrant into sub-quadrants. Each sub-quadrant would have the geohash value of the -containing quadrant concatenated with the value of the -sub-quadrant. The geohash for the upper-right quadrant is ``11``, and -the geohash for the sub-quadrants would be: (clockwise from the top -left) ``1101``, ``1111``, ``1110``, and ``1100``, respectfully. +containing quadrant concatenated with the value of the sub-quadrant. The +geohash for the upper-right quadrant is ``11``, and the geohash for the +sub-quadrants would be (clockwise from the top left): ``1101``, +``1111``, ``1110``, and ``1100``, respectively. + +To calculate a more precise geohash, continue dividing the sub-quadrant +and concatenate the two-bit identifier for each division. The more +"bits" in the hash identifier for a given point, the smaller possible +area that the hash can describe and the higher the resolution of the +geospatial index. + +Geospatial Indexes and Sharding +------------------------------- + +You *cannot* use a geospatial index as a :term:`shard key` when sharding a +collection. However, you *can* create and maintain a geospatial index +on a sharded collection, as long as the shard key is another +field. Your application may query for geospatial data using +:dbcommand:`geoNear` and :operator:`$within`; however, queries using +:operator:`$near` are not supported. + +.. _geospatial-indexes-multi-location: + +Multi-location Documents +------------------------ + +.. versionadded:: 2.0 + + Support for multiple locations in a document. + +In general, MongoDB cannot support more than one set of coordinates in +a document; however, using :ref:`multi-key indexes `, +you *can* index multiple coordinates in a single document. In the +simplest example, you may have a field (e.g. ``locs``) that holds an +array of geospatial coordinates, as in the following prototype data +model: + +.. code-block:: javascript + + { + "_id": ObjectId(...), + "locs": [ + [ 55.5, 42.3 ], + [ -74, 44.74 ], + { "lat": 55.3, "long": 40.2 } + ] + } + +The values of the array may either be arrays holding coordinates, as +in ``[ 55.5, 42.3 ]`` or embedded documents as in ``{ "lat": 55.3, +"long": 40.2 }``. + +You could then create a geospatial index on the ``locs`` field, as in +the following example: + +.. code-block:: javascript + + db.places.ensureIndex( { "locs": "2d" } ) + +You may also model the location data as a field inside of a +sub-document. In this case, the document would contain field +(e.g. ``addresses``) that held an array of documents where each +document has a field (e.g. ``loc:``) that holds location +coordinates. Consider the following prototype data model: + +.. code-block:: javascript + + { + "_id": ObjectId(...), + "name": "...", + "addresses": [ + { + "context": "home", + "loc": [ 55.5, 42.3 ] + }, + { + "context": "home", + "loc": [ -74, 44.74 ] + } + ] + } + +Then, create the geospatial index on the ``addresses.loc`` field as +in the following example: + +.. code-block:: javascript -To calculate a more precise :term:`geohash`, continue dividing the -sub-quadrant, concatenate the two-bit identifier for each division. The -more "bits" in the hash identifier for a given point, the smaller -possible area that the hash can describe, and the higher the -resolution of the geospatial index. + db.records.ensureIndex( { "addresses.loc": "2d" } ) -.. the following is a section about the limitations of geospatial - indexes in sharding: +For documents with multiple locations, results may have the same +document many times because of multiple matches. -.. include:: /includes/geospatial-sharding.rst +To include the location field with the distance field in +multi-location document queries, specify ``includeLocs: true`` +in the :dbcommand:`geoNear` command. \ No newline at end of file diff --git a/source/includes/geospatial-coordinates.rst b/source/includes/geospatial-coordinates.rst deleted file mode 100644 index 43f8afcb105..00000000000 --- a/source/includes/geospatial-coordinates.rst +++ /dev/null @@ -1,26 +0,0 @@ -Representing Coordinate Data ----------------------------- - -For geospatial indexes, you must model your coordinate data in a field -that holds a 2 dimensional array. The preferred form is: - -.. code-block:: javascript - - [ x, y ] - -Consistency is crucial: all documents must store the values in the -same order. You may also use an embedded document, as in: - -.. code-block:: javascript - - { x: 1, y: 2 } - -MongoDB will not read field names in embedded documents, so order is -still important when using this model. - -.. note:: - - If you use latitude/longitude data as your coordinate system, - always store latitude values first: MongoDB's :ref:`spherical - queries ` only recognize ``[ - latitude, longitude ]`` ordering. diff --git a/source/includes/geospatial-sharding.rst b/source/includes/geospatial-sharding.rst deleted file mode 100644 index dcdf4bb2ced..00000000000 --- a/source/includes/geospatial-sharding.rst +++ /dev/null @@ -1,9 +0,0 @@ -Geospatial Indexes and Sharding -------------------------------- - -You cannot use a geospatial index as a :term:`shard key` to shard a -collection. However, you *can* create and maintain a geospatial index -on a sharded collection, as long as the shard key is another -field. Your application may query for geospatial data using -:dbcommand:`geoNear` and :operator:`$within`; however, queries using -:operator:`$near` are not supported.