Geolocation field type and distance comparison

GraphQL queries for filtering by geolocation and distance from a fixed point

Skedulo supports GraphQL queries on the GeoLocation field type so that you can filter records based on the distance between a geolocation field and a fixed point. You can:

  • Query records based on their distance to a fixed geolocation.
  • Filter the results based on a distance greater than or less than a fixed number.
  • Order results by distance with support for NULLS FIRST and NULLS LAST.

The results are then returned in an order based on distance; either increasing (nearest to farthest) or decreasing (farthest to nearest).

This can be useful for populating the region field on a job based on the address. You can also use this feature to include or exclude resources within a specified distance or find the resource that is closest to a job location.

GeoLocation scalar type

Skedulo GraphQL supports a GeoLocation scalar type that allows you to use geolocation literals in EQL filters and orderBy clauses. Geolocation values are represented as strings in the format:

GEOLOCATION(latitude, longitude)

Where:

  • latitude and longitude are decimal numbers
  • Both coordinates can have up to 6 decimal places

Example geolocation literals

GEOLOCATION(37.774900, -122.419400)  // San Francisco
GEOLOCATION(0.000000, 0.000000)      // Equator/Prime Meridian
GEOLOCATION(-90.000000, -180.000000) // South Pole/Antimeridian
GEOLOCATION(35.123456, 45.654321)    // A geolocation with high precision coordinates

Filter and order geolocations

Regions include latitude and longitude fields, which are stored as a compound GeoLocation field for standard geolocation fields. In Skedulo, Lat and Lng fields have suffix Latitude and Longitude. The compound field always has suffix Location.

You can use these compound GeoLocation fields to filter and order the results of geolocation and distance comparison queries.

The Skedulo web application includes the GraphiQL web extension so that you can build and test GraphQL queries. Use either GraphiQL, or your preferred API client to create the geolocation and distance comparison query.

GeoLocation field selection

Important: GeoLocation fields cannot be queried directly in GraphQL field selection. If you need to access coordinate data, query the accompanying GeoLatitude and GeoLongitude decimal fields instead.

Example: Querying coordinate data

# ❌ This will fail - GeoLocation fields cannot be selected
query {
  regions {
    edges {
      node {
        UID
        Name
        GeoLocation  # Error: Field not available for selection
      }
    }
  }
}

# ✅ This works - use the accompanying decimal fields
query {
  regions {
    edges {
      node {
        UID
        Name
        GeoLatitude   # Available
        GeoLongitude  # Available
      }
    }
  }
}

Geolocation and distance comparison query

The GeoLocation query uses an EQL Filter to filter the regions based on their distance from a fixed GeoLocation point. The orderBy filter displays the results in either descending (DESC) or ascending (ASC) order of distance from the specified location. The orderBy mode is ASC by default.

In the following basic GraphQL example, we have created a query that requests the following information:

  • A list of regions, including the UID and Name fields.
  • Regions filtered in descending order based on their distance from the specified location, so the results will show the farthest region first, and the nearest region last.
  • The fixed geolocation from which we want to determine the region’s distance is 37.77, -122.42, which corresponds to San Francisco, California.
query queryRegions($filter: EQLQueryFilterRegions) {
  regions(filter: $filter, orderBy: "DISTANCE(GeoLocation, GEOLOCATION(37.77, -122.42)) DESC"){
    edges {
      node {
        UID
        Name
      }
    }
  }
}

We want to include regions that are within a set distance from the geolocation. The following filter variable uses the DISTANCE expression to specify that we want to display regions that are less than (<) 50000 meters from the geolocation for San Francisco:

{
  "filter": "DISTANCE(GeoLocation, GEOLOCATION(37.77, -122.42)) < 50000"
}

The following is an example response for the above query, where there are three regions listed within 50000 meters (50 kilometers) of GeoLocation 37.77, -122.42 (San Francisco).

{
  "data": {
    "regions": {
      "edges": [
        {
          "node": {
            "UID": "000314de-f629-4202-8a5b-c61f195f2fb0",
            "Name": "Oakland"
          }
        },
        {
          "node": {
            "UID": "0003e3a4-7bc5-441f-9e11-d8e4b7fbfad5",
            "Name": "San Jose"
          }
        },
        {
          "node": {
            "UID": "00038f3e-9e38-45e9-9e7b-9dec514a1199",
            "Name": "Berkeley"
          }
        }
      ]
    }
  }
}

Changing the orderBy filter to ASC will return the same results in the reverse order.

You can add more fields to the GraphQL query to return more information about the regions. For example, the following query also returns the Latitude and Longitude, Timezone and lists resources for which the region is their primary region.

query queryRegions($filter: EQLQueryFilterRegions) {
  regions(filter: $filter, orderBy: "DISTANCE(GeoLocation, GEOLOCATION(37.77, -122.42)) DESC"){
    edges {
      node {
        UID
        Name
        GeoLatitude
        GeoLongitude
        Timezone
        Resources {
        	UID
        	Name
        }
      }
    }
  }
}

This query returns the following response:

{
  "data": {
    "regions": {
      "edges": [
        {
          "node": {
            "UID": "000314de-f629-4202-8a5b-c61f195f2fb0",
            "Name": "Oakland",
            "Description": "East Bay (Oakland)",
            "GeoLatitude": 37.8044,
            "GeoLongitude": -122.2712,
            "Timezone": "America/Los_Angeles",
            "Resources": [
              {
                "UID": "000520bd-63a1-47a0-9c80-9a343cb35ec6",
                "Name": "David Kimi"
              }
            ]
          }
        },
        {
          "node": {
            "UID": "0003e3a4-7bc5-441f-9e11-d8e4b7fbfad5",
            "Name": "San Jose",
            "Description": "South Bay (San Jose)",
            "GeoLatitude": 37.3382,
            "GeoLongitude": -121.8863,
            "Timezone": "America/Los_Angeles",
            "Resources": [
              {
                "UID": "0005a7e9-b1aa-44da-937f-310b921b75cc",
                "Name": "John Smith"
              }
            ]
          }
        },
        {
          "node": {
            "UID": "00038f3e-9e38-45e9-9e7b-9dec514a1199",
            "Name": "Berkeley",
            "Description": "East Bay (Berkeley)",
            "GeoLatitude": 37.8715,
            "GeoLongitude": -122.2730,
            "Timezone": "America/Los_Angeles",
            "Resources": [
              {
                "UID": "000521e3-b4ab-417e-8fc2-23647246b085",
                "Name": "Mary Brown"
              }
            ]
          }
        }
      ]
    }
  }
}

You can also change the filter variable to return the regions farther or nearer using a different distance value, or by changing the comparison operator to show regions that are more than the specified distance value from the geolocation.

For example, the following variation to the filter distance comparison filters regions that are more than (>) 20000 meters (20 kilometers) from San Francisco:

{
  "filter": "DISTANCE(GeoLocation, GEOLOCATION(37.77, -122.42)) > 20000"
}

Advanced distance operations

Ordering with NULLS handling

You can specify how to handle null values when ordering by distance using NULLS FIRST or NULLS LAST:

query {
  regions(
    orderBy: "DISTANCE(GeoLocation, GEOLOCATION(37.77, -122.42)) ASC NULLS LAST"
  ) {
    edges {
      node {
        UID
        Name
        GeoLatitude
        GeoLongitude
      }
    }
  }
}

This query orders regions by distance from San Francisco, with regions that have no geolocation data appearing last in the results.

Complex distance filtering

You can combine distance operations with other EQL filters using boolean operators:

query {
  regions(
    filter: "DISTANCE(GeoLocation, GEOLOCATION(37.77, -122.42)) < 50000 AND Name LIKE '%San Francisco%'"
    orderBy: "DISTANCE(GeoLocation, GEOLOCATION(37.77, -122.42)) ASC"
  ) {
    edges {
      node {
        UID
        Name
        GeoLatitude
        GeoLongitude
      }
    }
  }
}

This query finds regions within 50km of San Francisco that have “San Francisco” in their name, ordered by distance.

Multiple distance ordering

You can combine distance ordering with other fields:

query {
  regions(
    orderBy: "DISTANCE(GeoLocation, GEOLOCATION(37.77, -122.42)) ASC, Name ASC"
  ) {
    edges {
      node {
        UID
        Name
        GeoLatitude
        GeoLongitude
      }
    }
  }
}

This query orders regions first by distance from San Francisco, then alphabetically by name for regions at the same distance.