Geo Queries

It is recommended to use AQL instead, see Geo functions.

The ArangoDB allows to select documents based on geographic coordinates. Inorder for this to work, a geo-spatial index must be defined. This index willuse a very elaborate algorithm to lookup neighbors that is a magnitude fasterthan a simple R* index.

In general a geo coordinate is a pair of latitude and longitude, which mustboth be specified as numbers. A geo index can be created on coordinates thatare stored in a single list attribute with two elements like [-10, +30] (latitude first, followed by longitude) or on coordinates stored in two separate attributes.

For example, to index the following documents, an index can be created on theposition attribute of the documents:

  1. db.test.save({ position: [ -10, 30 ] });
  2. db.test.save({ position: [ 10, 45.5 ] });
  3. db.test.ensureIndex({ type: "geo", fields: [ "position" ] });

If coordinates are stored in two distinct attributes, the index must be createdon the two attributes:

  1. db.test.save({ latitude: -10, longitude: 30 });
  2. db.test.save({ latitude: 10, longitude: 45.5 });
  3. db.test.ensureIndex({ type: "geo", fields: [ "latitude", "longitude" ] });

In order to find all documents within a given radius around a coordinate use the within operator. In order to find all documents near a given document use the near operator.

It is possible to define more than one geo-spatial index per collection. Inthis case you must give a hint using the geo operator which of indexesshould be used in a query.

Near

constructs a near query for a collectioncollection.near(latitude, longitude)

The returned list is sorted according to the distance, with the nearestdocument to the coordinate (latitude, longitude) coming first.If there are near documents of equal distance, documents are chosen randomlyfrom this set until the limit is reached. It is possible to change the limitusing the limit operator.

In order to use the near operator, a geo index must be defined for thecollection. This index also defines which attribute holds the coordinatesfor the document. If you have more then one geo-spatial index, you can usethe geo operator to select a particular index.

Note: near does not support negative skips.// However, you can still use limit followed to skip.

collection.near(latitude, longitude).limit(limit)

Limits the result to limit documents instead of the default 100.

Note: Unlike with multiple explicit limits, limit will raisethe implicit default limit imposed by within.

collection.near(latitude, longitude).distance()

This will add an attribute distance to all documents returned, whichcontains the distance between the given point and the document in meters.

collection.near(latitude, longitude).distance(name)

This will add an attribute name to all documents returned, whichcontains the distance between the given point and the document in meters.

Note: this method is not yet supported by the RocksDB storage engine.

Note: the near simple query function is deprecated as of ArangoDB 2.6.The function may be removed in future versions of ArangoDB. The preferredway for retrieving documents from a collection using the near operator isto use the AQL NEAR function in an AQL query as follows:

  1. FOR doc IN NEAR(@@collection, @latitude, @longitude, @limit)
  2. RETURN doc

Examples

To get the nearest two locations:

  1. arangosh> db.geo.ensureIndex({ type: "geo", fields: [ "loc" ] });
  2. {
  3. "bestIndexedLevel" : 17,
  4. "fields" : [
  5. "loc"
  6. ],
  7. "geoJson" : false,
  8. "id" : "geo/215",
  9. "isNewlyCreated" : true,
  10. "maxNumCoverCells" : 8,
  11. "name" : "idx_1655125937813979136",
  12. "sparse" : true,
  13. "type" : "geo",
  14. "unique" : false,
  15. "worstIndexedLevel" : 4,
  16. "code" : 201
  17. }
  18. arangosh> for (var i = -90; i <= 90; i += 10) {
  19. ........> for (var j = -180; j <= 180; j += 10) {
  20. ........> db.geo.save({
  21. ........> name : "Name/" + i + "/" + j,
  22. ........> loc: [ i, j ] });
  23. ........> } }
  24. arangosh> db.geo.near(0, 0).limit(2).toArray();
  25. [
  26. {
  27. "_key" : "921",
  28. "_id" : "geo/921",
  29. "_rev" : "_Z2KCT1O--C",
  30. "name" : "Name/0/0",
  31. "loc" : [
  32. 0,
  33. 0
  34. ]
  35. },
  36. {
  37. "_key" : "995",
  38. "_id" : "geo/995",
  39. "_rev" : "_Z2KCT2O--A",
  40. "name" : "Name/10/0",
  41. "loc" : [
  42. 10,
  43. 0
  44. ]
  45. }
  46. ]

Hide execution results

  1. arangosh> db.geo.ensureIndex({ type: "geo", fields: [ "loc" ] });
  2. arangosh> for (var i = -90; i <= 90; i += 10) {
  3. ........> for (var j = -180; j <= 180; j += 10) {
  4. ........> db.geo.save({
  5. ........> name : "Name/" + i + "/" + j,
  6. ........> loc: [ i, j ] });
  7. ........> } }
  8. arangosh> db.geo.near(0, 0).limit(2).toArray();

Show execution results

If you need the distance as well, then you can use the distanceoperator:

  1. arangosh> db.geo.ensureIndex({ type: "geo", fields: [ "loc" ] });
  2. {
  3. "bestIndexedLevel" : 17,
  4. "fields" : [
  5. "loc"
  6. ],
  7. "geoJson" : false,
  8. "id" : "geo/1636",
  9. "isNewlyCreated" : true,
  10. "maxNumCoverCells" : 8,
  11. "name" : "idx_1655125938139037698",
  12. "sparse" : true,
  13. "type" : "geo",
  14. "unique" : false,
  15. "worstIndexedLevel" : 4,
  16. "code" : 201
  17. }
  18. arangosh> for (var i = -90; i <= 90; i += 10) {
  19. ........> for (var j = -180; j <= 180; j += 10) {
  20. ........> db.geo.save({
  21. ........> name : "Name/" + i + "/" + j,
  22. ........> loc: [ i, j ] });
  23. ........> } }
  24. arangosh> db.geo.near(0, 0).distance().limit(2).toArray();
  25. [
  26. {
  27. "_id" : "geo/2342",
  28. "_key" : "2342",
  29. "_rev" : "_Z2KCUIK--A",
  30. "loc" : [
  31. 0,
  32. 0
  33. ],
  34. "name" : "Name/0/0",
  35. "distance" : 0
  36. },
  37. {
  38. "_id" : "geo/2416",
  39. "_key" : "2416",
  40. "_rev" : "_Z2KCUJG---",
  41. "loc" : [
  42. 10,
  43. 0
  44. ],
  45. "name" : "Name/10/0",
  46. "distance" : 1111949.2664455872
  47. }
  48. ]

Hide execution results

  1. arangosh> db.geo.ensureIndex({ type: "geo", fields: [ "loc" ] });
  2. arangosh> for (var i = -90; i <= 90; i += 10) {
  3. ........> for (var j = -180; j <= 180; j += 10) {
  4. ........> db.geo.save({
  5. ........> name : "Name/" + i + "/" + j,
  6. ........> loc: [ i, j ] });
  7. ........> } }
  8. arangosh> db.geo.near(0, 0).distance().limit(2).toArray();

Show execution results

Within

constructs a within query for a collectioncollection.within(latitude, longitude, radius)

This will find all documents within a given radius around the coordinate(latitude, longitude). The returned array is sorted by distance,beginning with the nearest document.

In order to use the within operator, a geo index must be defined for thecollection. This index also defines which attribute holds the coordinatesfor the document. If you have more then one geo-spatial index, you can usethe geo operator to select a particular index.

collection.within(latitude, longitude, radius).distance()

This will add an attribute _distance to all documents returned, whichcontains the distance between the given point and the document in meters.

collection.within(latitude, longitude, radius).distance(name)

This will add an attribute name to all documents returned, whichcontains the distance between the given point and the document in meters.

Note: this method is not yet supported by the RocksDB storage engine.

Note: the within simple query function is deprecated as of ArangoDB 2.6.The function may be removed in future versions of ArangoDB. The preferredway for retrieving documents from a collection using the within operator isto use the AQL WITHIN function in an AQL query as follows:

  1. FOR doc IN WITHIN(@@collection, @latitude, @longitude, @radius, @distanceAttributeName)
  2. RETURN doc

Examples

To find all documents within a radius of 2000 km use:

  1. arangosh> for (var i = -90; i <= 90; i += 10) {
  2. ........> for (var j = -180; j <= 180; j += 10) {
  3. ........> db.geo.save({ name : "Name/" + i + "/" + j, loc: [ i, j ] }); } }
  4. arangosh> db.geo.within(0, 0, 2000 * 1000).distance().toArray();
  5. [
  6. {
  7. "_id" : "geo/3763",
  8. "_key" : "3763",
  9. "_rev" : "_Z2KCUau--C",
  10. "loc" : [
  11. 0,
  12. 0
  13. ],
  14. "name" : "Name/0/0",
  15. "distance" : 0
  16. },
  17. {
  18. "_id" : "geo/3837",
  19. "_key" : "3837",
  20. "_rev" : "_Z2KCUbq--C",
  21. "loc" : [
  22. 10,
  23. 0
  24. ],
  25. "name" : "Name/10/0",
  26. "distance" : 1111949.2664455872
  27. },
  28. {
  29. "_id" : "geo/3765",
  30. "_key" : "3765",
  31. "_rev" : "_Z2KCUay---",
  32. "loc" : [
  33. 0,
  34. 10
  35. ],
  36. "name" : "Name/0/10",
  37. "distance" : 1111949.2664455872
  38. },
  39. {
  40. "_id" : "geo/3689",
  41. "_key" : "3689",
  42. "_rev" : "_Z2KCUZy--C",
  43. "loc" : [
  44. -10,
  45. 0
  46. ],
  47. "name" : "Name/-10/0",
  48. "distance" : 1111949.2664455872
  49. },
  50. {
  51. "_id" : "geo/3761",
  52. "_key" : "3761",
  53. "_rev" : "_Z2KCUau--A",
  54. "loc" : [
  55. 0,
  56. -10
  57. ],
  58. "name" : "Name/0/-10",
  59. "distance" : 1111949.2664455872
  60. },
  61. {
  62. "_id" : "geo/3687",
  63. "_key" : "3687",
  64. "_rev" : "_Z2KCUZy--A",
  65. "loc" : [
  66. -10,
  67. -10
  68. ],
  69. "name" : "Name/-10/-10",
  70. "distance" : 1568520.556798576
  71. },
  72. {
  73. "_id" : "geo/3839",
  74. "_key" : "3839",
  75. "_rev" : "_Z2KCUbu---",
  76. "loc" : [
  77. 10,
  78. 10
  79. ],
  80. "name" : "Name/10/10",
  81. "distance" : 1568520.556798576
  82. },
  83. {
  84. "_id" : "geo/3835",
  85. "_key" : "3835",
  86. "_rev" : "_Z2KCUbq--A",
  87. "loc" : [
  88. 10,
  89. -10
  90. ],
  91. "name" : "Name/10/-10",
  92. "distance" : 1568520.556798576
  93. },
  94. {
  95. "_id" : "geo/3691",
  96. "_key" : "3691",
  97. "_rev" : "_Z2KCUZ2---",
  98. "loc" : [
  99. -10,
  100. 10
  101. ],
  102. "name" : "Name/-10/10",
  103. "distance" : 1568520.556798576
  104. }
  105. ]

Hide execution results

  1. arangosh> for (var i = -90; i <= 90; i += 10) {
  2. ........> for (var j = -180; j <= 180; j += 10) {
  3. ........> db.geo.save({ name : "Name/" + i + "/" + j, loc: [ i, j ] }); } }
  4. arangosh> db.geo.within(0, 0, 2000 * 1000).distance().toArray();

Show execution results

Geo

constructs a geo index selectioncollection.geo(location-attribute)

Looks up a geo index defined on attribute location_attribute.

Returns a geo index object if an index was found. The near orwithin operators can then be used to execute a geo-spatial query onthis particular index.

This is useful for collections with multiple defined geo indexes.

collection.geo(location_attribute, true)

Looks up a geo index on a compound attribute location_attribute.

Returns a geo index object if an index was found. The near orwithin operators can then be used to execute a geo-spatial query onthis particular index.

collection.geo(latitude_attribute, longitude_attribute)

Looks up a geo index defined on the two attributes latitude_attribute_and _longitude-attribute.

Returns a geo index object if an index was found. The near orwithin operators can then be used to execute a geo-spatial query onthis particular index.

Note: this method is not yet supported by the RocksDB storage engine.

Note: the geo simple query helper function is deprecated as of ArangoDB2.6. The function may be removed in future versions of ArangoDB. The preferredway for running geo queries is to use their AQL equivalents.

Examples

Assume you have a location stored as list in the attribute home_and a destination stored in the attribute _work. Then you can use thegeo operator to select which geo-spatial attributes (and thus whichindex) to use in a near query.

  1. arangosh> for (i = -90; i <= 90; i += 10) {
  2. ........> for (j = -180; j <= 180; j += 10) {
  3. ........> db.complex.save({ name : "Name/" + i + "/" + j,
  4. ........> home : [ i, j ],
  5. ........> work : [ -i, -j ] });
  6. ........> }
  7. ........> }
  8. ........>
  9. arangosh> db.complex.near(0, 170).limit(5);
  10. [ArangoError 1570: no suitable geo index found for geo restriction on 'complex']
  11. arangosh> db.complex.ensureIndex({ type: "geo", fields: [ "home" ] });
  12. {
  13. "bestIndexedLevel" : 17,
  14. "fields" : [
  15. "home"
  16. ],
  17. "geoJson" : false,
  18. "id" : "complex/86125",
  19. "isNewlyCreated" : true,
  20. "maxNumCoverCells" : 8,
  21. "name" : "idx_1655126005418819585",
  22. "sparse" : true,
  23. "type" : "geo",
  24. "unique" : false,
  25. "worstIndexedLevel" : 4,
  26. "code" : 201
  27. }
  28. arangosh> db.complex.near(0, 170).limit(5).toArray();
  29. [
  30. {
  31. "_key" : "85454",
  32. "_id" : "complex/85454",
  33. "_rev" : "_Z2KDSjO--A",
  34. "name" : "Name/0/170",
  35. "home" : [
  36. 0,
  37. 170
  38. ],
  39. "work" : [
  40. 0,
  41. -170
  42. ]
  43. },
  44. {
  45. "_key" : "85456",
  46. "_id" : "complex/85456",
  47. "_rev" : "_Z2KDSjO--C",
  48. "name" : "Name/0/180",
  49. "home" : [
  50. 0,
  51. 180
  52. ],
  53. "work" : [
  54. 0,
  55. -180
  56. ]
  57. },
  58. {
  59. "_key" : "85528",
  60. "_id" : "complex/85528",
  61. "_rev" : "_Z2KDSj6--A",
  62. "name" : "Name/10/170",
  63. "home" : [
  64. 10,
  65. 170
  66. ],
  67. "work" : [
  68. -10,
  69. -170
  70. ]
  71. },
  72. {
  73. "_key" : "85380",
  74. "_id" : "complex/85380",
  75. "_rev" : "_Z2KDSii--C",
  76. "name" : "Name/-10/170",
  77. "home" : [
  78. -10,
  79. 170
  80. ],
  81. "work" : [
  82. 10,
  83. -170
  84. ]
  85. },
  86. {
  87. "_key" : "85384",
  88. "_id" : "complex/85384",
  89. "_rev" : "_Z2KDSim---",
  90. "name" : "Name/0/-180",
  91. "home" : [
  92. 0,
  93. -180
  94. ],
  95. "work" : [
  96. 0,
  97. 180
  98. ]
  99. }
  100. ]
  101. arangosh> db.complex.geo("work").near(0, 170).limit(5);
  102. [ArangoError 1570: no suitable geo index found for geo restriction on 'complex']
  103. arangosh> db.complex.ensureIndex({ type: "geo", fields: [ "work" ] });
  104. {
  105. "bestIndexedLevel" : 17,
  106. "fields" : [
  107. "work"
  108. ],
  109. "geoJson" : false,
  110. "id" : "complex/86134",
  111. "isNewlyCreated" : true,
  112. "maxNumCoverCells" : 8,
  113. "name" : "idx_1655126005425111040",
  114. "sparse" : true,
  115. "type" : "geo",
  116. "unique" : false,
  117. "worstIndexedLevel" : 4,
  118. "code" : 201
  119. }
  120. arangosh> db.complex.geo("work").near(0, 170).limit(5).toArray();
  121. [
  122. {
  123. "_key" : "85454",
  124. "_id" : "complex/85454",
  125. "_rev" : "_Z2KDSjO--A",
  126. "name" : "Name/0/170",
  127. "home" : [
  128. 0,
  129. 170
  130. ],
  131. "work" : [
  132. 0,
  133. -170
  134. ]
  135. },
  136. {
  137. "_key" : "85456",
  138. "_id" : "complex/85456",
  139. "_rev" : "_Z2KDSjO--C",
  140. "name" : "Name/0/180",
  141. "home" : [
  142. 0,
  143. 180
  144. ],
  145. "work" : [
  146. 0,
  147. -180
  148. ]
  149. },
  150. {
  151. "_key" : "85528",
  152. "_id" : "complex/85528",
  153. "_rev" : "_Z2KDSj6--A",
  154. "name" : "Name/10/170",
  155. "home" : [
  156. 10,
  157. 170
  158. ],
  159. "work" : [
  160. -10,
  161. -170
  162. ]
  163. },
  164. {
  165. "_key" : "85380",
  166. "_id" : "complex/85380",
  167. "_rev" : "_Z2KDSii--C",
  168. "name" : "Name/-10/170",
  169. "home" : [
  170. -10,
  171. 170
  172. ],
  173. "work" : [
  174. 10,
  175. -170
  176. ]
  177. },
  178. {
  179. "_key" : "85384",
  180. "_id" : "complex/85384",
  181. "_rev" : "_Z2KDSim---",
  182. "name" : "Name/0/-180",
  183. "home" : [
  184. 0,
  185. -180
  186. ],
  187. "work" : [
  188. 0,
  189. 180
  190. ]
  191. }
  192. ]

Hide execution results

  1. arangosh> for (i = -90; i <= 90; i += 10) {
  2. ........> for (j = -180; j <= 180; j += 10) {
  3. ........> db.complex.save({ name : "Name/" + i + "/" + j,
  4. ........> home : [ i, j ],
  5. ........> work : [ -i, -j ] });
  6. ........> }
  7. ........> }
  8. ........>
  9. arangosh> db.complex.near(0, 170).limit(5);
  10. arangosh> db.complex.ensureIndex({ type: "geo", fields: [ "home" ] });
  11. arangosh> db.complex.near(0, 170).limit(5).toArray();
  12. arangosh> db.complex.geo("work").near(0, 170).limit(5);
  13. arangosh> db.complex.ensureIndex({ type: "geo", fields: [ "work" ] });
  14. arangosh> db.complex.geo("work").near(0, 170).limit(5).toArray();

Show execution results

Other ArangoDB geographic features are described in: