Geospatial Queries

Geospatial Queries

Geospatial queries return documents that contain location-data.

Introduction to Geospatial Querying

A geospatial query specifies a location, and returns each document that contains a proximity-match. A location is represented by means of longitude-latitude coordinate pairs.

This allows an application, based on the user's input of a particular coordinate, address, or property name, to derive a list of points of interest that lie within a specified distance of the user-referenced location; and display these for the user's benefit.

The location-data provided by a geospatial query can be either of the following:

  • A location, specified as a longitude-latitude coordinate pair; and a distance, in miles. The location determines the center of a circle whose radius-length is the specified distance. Documents are returned if they reference a location within the circle.

  • Two longitude-latitude coordinate pairs. These are respectively taken to indicate the top left and bottom right corners of a bounding box. Documents are returned if they reference a location within the box.

To be successful, a geospatial query must reference an index within which the geopoint type mapping has been applied to the field containing the target longitude-latitude coordinate pair.

Recognizing Target Data

The travel-sample bucket, provided for test and development, contains multiple documents that specify locations. For example, those that represent airports, such as airport_1254:

{
  "airportname": "Calais Dunkerque",
  "city": "Calais",
  "country": "France",
  "faa": "CQF",
  "geo": {
    "alt": 12,
    "lat": 50.962097,
    "lon": 1.954764
  },
  "icao": "LFAC",
  "id": 1254,
  "type": "airport",
  "tz": "Europe/Paris"
}

The geo field contains the lon and lat key-value pairs. Such a parent-field is accessed directly by a geospatial query: the internal long and lat child-fields are not explicitly specified. Moreover, any other child-field, such as alt, is ignored.

For information on installing the travel-sample bucket, see Install Sample Buckets.

Creating a Geospatial Index

To be successful, a geospatial query must reference an index that applies the geopoint type mapping to the field containing the longitude-latitude coordinate pair. This can be achieved by means of the Couchbase Web Console. Detailed instructions for setting up indexes, and specifying type mappings, are provided in Creating Indexes. For initial experimentation with geospatial querying, the geo field of documents within the travel-sample bucket can be specified as a child mapping of the default type mapping, as follows:

The index so created can also be specified by means of the Couchbase REST API. See Demonstration Indexes for the body of the index to be used, and see Index-Creation with the REST API for information on using the REST syntax.

Creating a Query: Radius-Based

This section and the following provide examples of the query-bodies required to make geospatial queries with the Couchbase REST API. Note that more detailed information on performing queries with the Couchbase REST API can be found in Searching with the REST API; which shows how to use the full curl command, and how to incorporate query-bodies into it.

The following query-body specifies a longitude of -2.235143, and a latitude of 53.482358. The target-field geo is specified, as is a distance of 100 miles: this is the radius within which target-locations must reside, for their documents to be returned.

{
  "from": 0,
  "size": 10,
  "query": {
    "location": {
      "lon": -2.235143,
      "lat": 53.482358
     },
      "distance": "100mi",
      "field": "geo"
    },
  "sort": [
    {
      "by": "geo_distance",
      "field": "geo",
      "unit": "mi",
      "location": {
      "lon": -2.235143,
      "lat": 53.482358
      }
    }
  ]
}

Note that the longitude-latitude coordinate pair can also be specified as an array, if desired. The lon value must always precede the lat:

"location": [-2.235143, 53.482358],

The query also contains a sort object, which specifies that the returned documents should be ordered in terms of their geo_distance from specified lon and lat coordinates: these values need not be identical to those specified in the query object.

A subset of formatted console output might appear as follows:

            .
            .
            .
"hits": [
  {
    "index": "geoIndex_61d8c796ef7f4360_acbbef99",
    "id": "landmark_17411",
    "score": 1.4045076008239446e-06,
    "sort": [
      " \u0001?E#9>N\f\"e"
    ]
  },
  {
    "index": "geoIndex_61d8c796ef7f4360_acbbef99",
    "id": "landmark_17409",
    "score": 1.4045076008239446e-06,
    "sort": [
      " \u0001?O~i*(kD,"
    ]
  },
  {
    "index": "geoIndex_61d8c796ef7f4360_acbbef99",
    "id": "landmark_17403",
    "score": 1.4045076008239446e-06,
    "sort": [
      " \u0001?Sg*|/t\u001f\u0002"
    ]
  },
  {
    "index": "geoIndex_61d8c796ef7f4360_acbbef99",
    "id": "hotel_17413",
    "score": 1.4045076008239446e-06,
    "sort": [
      " \u0001?U]S\\.e\u0002_"
   ]
  },
            .
            .
            .

Creating a Query: Box-Based

The following query body forms the top_left corner of a bounding box, by means of a longitude of -2.235143 and a latitude of 53.482358. It also forms the botom_right, by means of 28.955043 and 40.991862. If a target data-location falls within the box, its document is returned. The results are specified to be sorted on name alone.

{ 
  "from": 0,
  "size": 10,
  "query": {
    "top_left": {
      "lon": -2.235143,
      "lat": 53.482358
     },
    "bottom_right": {
      "lon": 28.955043,
      "lat": 40.991862
     },
    "field": "geo"
  },
  "sort": [
    "name"
  ]
}

A subset of formatted output might appear as follows:

          .
          .
          .
"hits": [
  {
    "index": "geoIndex_61d8c796ef7f4360_acbbef99",
    "id": "landmark_17411",
    "score": 1.4045076008239446e-06,
    "sort": [
      " \u0001?E#9>N\f\"e"
    ]
  },
  {
    "index": "geoIndex_61d8c796ef7f4360_acbbef99",
    "id": "landmark_17409",
    "score": 1.4045076008239446e-06,
    "sort": [
      " \u0001?O~i*(kD,"
    ]
  },
  {
    "index": "geoIndex_61d8c796ef7f4360_acbbef99",
    "id": "landmark_17403",
    "score": 1.4045076008239446e-06,
    "sort": [
      " \u0001?Sg*|/t\u001f\u0002"
    ]
  },
  {
    "index": "geoIndex_61d8c796ef7f4360_acbbef99",
    "id": "hotel_17413",
    "score": 1.4045076008239446e-06,
    "sort": [
      " \u0001?U]S\\.e\u0002_"
    ]
  },
          .
          .
          .