Make a Spatial Query


  • Documents that contain spatial data can be queried by spatial queries that employ geographical criteria.
    You have two options:

    • Dynamic spatial query
      Either make a dynamic spatial query on a collection ( described in this article ).
      An auto-index will be created by the server.

    • Spatial index query
      Or, index your documents' spatial data in a static-index (see indexing spatial data),
      and then make a spatial query on this index (see query a spatial index).

  • To perform a spatial search,
    use the spatial method which provides a wide range of spatial functionalities.

  • When making a dynamic spatial query from the Studio,
    results are also displayed on the global map. See spatial queries map view.



Search by radius

Use the withinRadius method to search for all documents containing spatial data that is located
within the specified distance from the given center point.

// This query will return all matching employee entities
// that are located within 20 kilometers radius
// from point (47.623473 latitude, -122.3060097 longitude).

// Define a dynamic query on 'employees' collection
const employeesWithinRadius = await session
    .query({ collection: "employees" })
     // Call 'spatial' method
    .spatial(
        // Specify the  document fields containing the spatial data
        new PointField("address.location.latitude", "address.location.longitude"),
        // Set the geographical area in which to search for matching documents
        // Call 'withinRadius', pass the radius and the center points coordinates  
        criteria => criteria.withinRadius(20, 47.623473, -122.3060097))
    .all();
// This query will return all matching employee entities
// that are located within 20 kilometers radius
// from point (47.623473 latitude, -122.3060097 longitude).

from "employees"
where spatial.within(
    spatial.point(address.location.latitude, address.location.longitude),
    spatial.circle(20, 47.623473, -122.3060097)
)

Search by shape

  • Use the relatesToShape method to search for all documents containing spatial data that is located
    in the specified relation to the given shape.

  • The shape is specified as either a circle or a polygon in a WKT format.

  • The relation to the shape can be one of: Within, Contains, Disjoint, Intersects.

Circle:

// This query will return all matching employee entities
// that are located within 20 kilometers radius
// from point (47.623473 latitude, -122.3060097 longitude).

// Define a dynamic query on 'employees' collection
const employeesWithinShape = await session
    .query({ collection: "employees" })
     // Call 'spatial' method
    .spatial(
        // Specify the  document fields containing the spatial data
        new PointField("address.location.latitude", "address.location.longitude"),
        // Set the geographical search criteria, call 'relatesToShape'
        criteria => criteria.relatesToShape(
            // Specify the WKT string. Note: longitude is written FIRST
            "CIRCLE(-122.3060097 47.623473 d=20)",
            // Specify the relation between the WKT shape and the documents spatial data
            "Within",
            // Customize radius units (default is Kilometers) and error percentage (Optional)
            "Miles",
            0))
    .all();
// This query will return all matching employee entities
// that are located within 20 kilometers radius
// from point (47.623473 latitude, -122.3060097 longitude).

from "employees"
where spatial.within(
    spatial.point(address.location.latitude, address.location.longitude),
    spatial.wkt("CIRCLE(-122.3060097 47.623473 d=20)", "miles")
)

Polygon:

// This query will return all matching company entities
// that are located within the specified polygon.

// Define a dynamic query on 'companies' collection
const companiesWithinShape = await session
    .query({ collection: "employees" })
    // Call 'spatial' method
    .spatial(
        // Specify the  document fields containing the spatial data
        new PointField("address.location.latitude", "address.location.longitude"),
        // Set the geographical search criteria, call 'relatesToShape'
        criteria => criteria.relatesToShape(
            // Specify the WKT string
            `POLYGON ((
                -118.6527948 32.7114894,
                -95.8040242 37.5929338,
                -102.8344151 53.3349629,
                -127.5286633 48.3485664,
                -129.4620208 38.0786067,
                -118.7406746 32.7853769,
                -118.6527948 32.7114894
            ))`,
            // Specify the relation between the WKT shape and the documents spatial data
            "Within"))
    .all(); 
// This query will return all matching company entities
// that are located within the specified polygon.

from "companies"
where spatial.within(
    spatial.point(address.location.latitude, address.location.longitude),
    spatial.wkt("POLYGON ((
        -118.6527948 32.7114894,
        -95.8040242 37.5929338,
        -102.8344151 53.3349629,
        -127.5286633 48.3485664,
        -129.4620208 38.0786067,
        -118.7406746 32.7853769,
        -118.6527948 32.7114894))")
)

Polygon rules:

  • The polygon's coordinates must be provided in counterclockwise order.

  • The first and last coordinates must mark the same location to form a closed region.

WKT polygon

WKT Polygon

Spatial sorting

  • Use orderByDistance or orderByDistanceDescending to sort the results by distance from a given point.

  • By default, distance in RavenDB measured in kilometers.
    The distance can be rounded to a specific range.

Order by distance:

// Return all matching employee entities located within 20 kilometers radius
// from point (47.623473 latitude, -122.3060097 longitude).

// Sort the results by their distance from a specified point,
// the closest results will be listed first.

const employeesSortedByDistance = await session
    .query({ collection: "employees" })
     // Provide the query criteria:
    .spatial(
        new PointField("address.location.latitude", "address.location.longitude"),
        criteria => criteria.withinRadius(20, 47.623473, -122.3060097))
     // Call 'orderByDistance'
    .orderByDistance(
        // Specify the document fields containing the spatial data
        new PointField("address.location.latitude", "address.location.longitude"),
        // Sort the results by their distance from this point: 
        47.623473, -122.3060097)
    .all();
// Return all matching employee entities located within 20 kilometers radius
// from point (47.623473 latitude, -122.3060097 longitude).

// Sort the results by their distance from a specified point,
// the closest results will be listed first.

from "employees"
where spatial.within(
    spatial.point(address.location.latitude, address.location.longitude),
    spatial.circle(20, 47.623473, -122.3060097)
)
order by spatial.distance(
    spatial.point(address.location.latitude, address.location.longitude),
    spatial.point(47.623473, -122.3060097)
)

Order by distance descending:

// Return all employee entities sorted by their distance from a specified point.
// The farthest results will be listed first.

const employeesSortedByDistanceDesc = await session
    .query({ collection: "employees" })
     // Call 'orderByDistanceDescending'
    .orderByDistanceDescending(
        // Specify the document fields containing the spatial data
        new PointField("address.location.latitude", "address.location.longitude"),
        // Sort the results by their distance (descending) from this point: 
        47.623473, -122.3060097)
    .all();
// Return all employee entities sorted by their distance from a specified point.
// The farthest results will be listed first.

from "employees"
order by spatial.distance(
    spatial.point(address.location.latitude, address.location.longitude),
    spatial.point(47.623473, -122.3060097)
) desc

Sort results by rounded distance:

// Return all employee entities.
// Results are sorted by their distance to a specified point rounded to the nearest 100 km interval.
// A secondary sort can be applied within the 100 km range, e.g. by field lastName.

const employeesSortedByRoundedDistance = await session
    .query({ collection: "employees" })
     // Call 'orderByDistanceDescending'
    .orderByDistance(
        // Specify the document fields containing the spatial data
        new PointField("address.location.latitude", "address.location.longitude")
             // Round up distance to 100 km 
            .roundTo(100),
        // Sort the results by their distance (descending) from this point: 
        47.623473, -122.3060097)
     // A secondary sort can be applied
    .orderBy("lastName")
    .all();
// Return all employee entities.
// Results are sorted by their distance to a specified point rounded to the nearest 100 km interval.
// A secondary sort can be applied within the 100 km range, e.g. by field lastName.

from "employees"
order by spatial.distance(
    spatial.point(address.location.latitude, address.location.longitude),
    spatial.point(47.623473, -122.3060097),
    100
), lastName

Get resulting distance:

  • The distance is available in the @spatial metadata property within each result.

  • Note the following difference between the underlying search engines:

    • When using Lucene:
      This metadata property is always available in the results.

    • When using Corax:
      In order to enhance performance, this property is not included in the results by default.
      To get this metadata property you must set the Indexing.Corax.IncludeSpatialDistance configuration value to true.
      Learn about the available methods for setting an indexing configuration key in this indexing-configuration article.

// Get the distance of the results:
// ================================

// Call 'GetMetadataFor', pass an entity from the resulting employees list
const metadata = session.advanced.getMetadataFor(employeesSortedByDistance[0]);

// The distance is available in the '@spatial' metadata property
const spatialResults = metadata["@spatial"];

const distance = spatialResults.Distance;   // The distance of the entity from the queried location
const latitude = spatialResults.Latitude;   // The entity's longitude value
const longitude = spatialResults.Longitude; // The entity's longitude value

Spatial API


spatial

spatial(fieldName, clause);
spatial(field, clause);
Parameters Type Description
fieldName string Path to spatial field in an index
(when querying an index).
field DynamicSpatialField Object that contains the document's spatial fields,
either PointField or WktField
(when making a dynamic query).
clause (SpatialCriteriaFactory) => SpatialCrieteria Spatial criteria that will be executed on a given spatial field.

DynamicSpatialField

class PointField {
    latitude; 
    longitude;
}

class WktField {
    wkt;
}
Parameters Type Description
latitude string Path to the document field that contains the latitude
longitude string Path to the document field that contains the longitude
wktPath string Path to the document field that contains the WKT string

SpatialCriteriaFactory

relatesToShape(shapeWkt, relation);
relatesToShape(shapeWkt, relation, units, distErrorPercent);
intersects(shapeWkt);
intersects(shapeWkt, distErrorPercent);
intersects(shapeWkt, distErrorPercent);
intersects(shapeWkt, units, distErrorPercent);
contains(shapeWkt);
contains(shapeWkt, units);
contains(shapeWkt, distErrorPercent);
contains(shapeWkt, units, distErrorPercent);
disjoint(shapeWkt);
disjoint(shapeWkt, units);
disjoint(shapeWkt, distErrorPercent);
disjoint(shapeWkt, units, distErrorPercent);
within(shapeWkt);
within(shapeWkt, units);
within(shapeWkt, distErrorPercent);
within(shapeWkt, units, distErrorPercent);
withinRadius(radius, latitude, longitude);
withinRadius(radius, latitude, longitude, radiusUnits);
withinRadius(radius, latitude, longitude, radiusUnits, distErrorPercent);
Parameter Type Description
shapeWkt string WKT-based shape used in query criteria
relation string Relation of the shape to the spatial data in the document/index.
Can be Within, Contains, Disjoint, Intersects.
distErrorPercent number Maximum distance error tolerance in percents. Default: 0.025
radius / latitude / longitude number Used to define a radius of a circle
radiusUnits / units string Determines if circle or shape should be calculated in Kilometers or Miles.
By default, distances are measured in kilometers.

orderByDistance

orderByDistance(field, latitude, longitude);
orderByDistance(field, shapeWkt);
orderByDistance(fieldName, latitude, longitude);
orderByDistance(fieldName, latitude, longitude, roundFactor: number);
orderByDistance(fieldName, shapeWkt);

orderByDistanceDescending

orderByDistanceDescending(field, latitude, longitude);
orderByDistanceDescending(field, shapeWkt);
orderByDistanceDescending(fieldName, latitude, longitude);
orderByDistanceDescending(fieldName, latitude, longitude, roundFactor);
orderByDistanceDescending(fieldName, shapeWkt);
Parameter Type Description
fieldName string Path to spatial field in index
(when querying an index).
field DynamicSpatialField Object that contains the document's spatial fields,
either PointField or WktField
(when making a dynamic query).
shapeWkt string WKT-based shape to be used as a point from which distance will be measured. If the shape is not a single point, then the center of the shape will be used as a reference.
latitude / longitude number Used to define a point from which distance will be measured
roundFactor number A distance interval in kilometers.
The distance from the point is rounded up to the nearest interval.
The results within the same interval can be sorted by a secondary order.
If no other order was specified, then by ascending order of document Id.