Writing geospatial views

Geospatial support was introduced as an experimental feature in Couchbase Server. This feature is currently unsupported and is provided only for the purposes of demonstration and testing.

GeoCouch adds two-dimensional spatial index support to Couchbase. Spatial support enables you to record geometry data into the bucket and then perform queries which return information based on whether the recorded geometries existing within a given two-dimensional range such as a bounding box. This can be used in spatial queries and in particular geolocationary queries where you want to find entries based on your location or region.

The GeoCouch support is provided through updated index support and modifications to the view engine to provide advanced geospatial queries.

Adding geometry data

GeoCouch supports the storage of any geometry information using the GeoJSON specification. The format of the storage of the point data is arbitrary with the geometry type being supported during the view index generation.

For example, you can use two-dimensional geometries for storing simple location data. You can add these to your Couchbase documents using any field name. The convention is to use a single field with two-element array with the point location, but you can also use two separate fields or compound structures as it is the view that compiles the information into the geospatial index.

For example, to populate a bucket with city location information, the document sent to the bucket could be formatted like that below:

{
"loc" : [-122.270833, 37.804444],
"title" : "Oakland"
}

Views and queries

The GeoCouch extension uses the standard Couchbase indexing system to build a two-dimensional index from the point data within the bucket. The format of the index information is based on the GeoJSON specification.

To create a geospatial index, use the emit() function to output a GeoJSON Point value containing the coordinates of the point you are describing. For example, the following function will create a geospatial index on the earlier spatial record example.

function(doc, meta)
{
  if (doc.loc)
  {
     emit(
          {
             type: "Point",
             coordinates: doc.loc,
          },
          [meta.id, doc.loc]);
  }
}

The key in the spatial view index can be any valid GeoJSON geometry value, including points, multipoints, linestrings, polygons and geometry collections.

The view map() function should be placed into a design document using the spatial prefix to indicate the nature of the view definition. For example, the following design document includes the above function as the view points

{
   "spatial" : {
      "points" : "function(doc, meta) { if (doc.loc) { emit({ type: \"Point\", coordinates: doc.loc}, [meta.id, doc.loc]);}}",
   }
}

To execute the geospatial query you use the design document format using the embedded spatial indexing. For example, if the design document is called main within the bucket places, the URL will be http://localhost:8092/places/_design/main/_spatial/points.

Spatial queries include support for a number of additional arguments to the view request. The full list is provided in the following summary table.

Get Spatial Name Description
Method GET /bucket/_design/design-doc/_spatial/spatial-name
Request Data None
Response Data JSON of the documents returned by the view
Authentication Required no
  Query Arguments
bbox Specify the bounding box for a spatial query
  Parameters : string; optional
limit Limit the number of the returned documents to the specified number
  Parameters : numeric; optional
skip Skip this number of records before starting to return the results
  Parameters : numeric; optional
stale Allow the results from a stale view to be used
  Parameters : string; optional
  Supported Values
  false : Force update of the view index before results are returned
  ok : Allow stale views
  update_after : Allow stale view, update view after access

Bounding Box Queries If you do not supply a bounding box, the full dataset is returned. When querying a spatial index you can use the bounding box to specify the boundaries of the query lookup on a given value. The specification should be in the form of a comma-separated list of the coordinates to use during the query.

These coordinates are specified using the GeoJSON format, so the first two numbers are the lower left coordinates, and the last two numbers are the upper right coordinates.

For example, using the above design document:

GET http://localhost:8092/places/_design/main/_spatial/points?bbox=-180,-90,0,0
Content-Type: application/json

Returns the following information:

{
    "total_rows": 0,
    "rows": [
        {
            "id": "oakland",
            "key": [
                [
                    -122.270833,
                    -122.270833
                ],
                [
                    37.804444,
                    37.804444
                ]
            ],
            "value": [
                "oakland",
                [
                    -122.270833,
                    37.804444
                ]
            ],
            "geometry": {
                "coordinates": [
                    -122.270833,
                    37.804444
                ],
                "type": "Point"
            }
        }
    ]
}
Note: The return data includes the value specified in the design document view function, and the bounding box of each individual matching document. If the spatial index includes the bbox bounding box property as part of the specification, then this information will be output in place of the automatically calculated version.