Quantcast
Channel: Brian Pedersen's Sitecore and .NET Blog
Viewing all articles
Browse latest Browse all 286

C# CosmosDB spatial geographic search using GeoJSON coordinates

$
0
0

If you have data in an Azure CosmosDB, it is possible to perform spatial location based searches, returning documents within a distance from a point, or within a certain area.

The first thing you need, is to store the longitude and latitude in a GeoJSON object. Having the coordinates in ordinary fields will not allow you to do a geographic search.

The GeoJSON object have the following format:

{
    "type": "Point",
    "coordinates": [
        <longitude>,
        <latitude>
    ]
}

A correctly formatted object in CosmosDB look like this:

GeoJSON object in CosmosDB
GeoJSON object in CosmosDB

With that data, you can perform a location based search.

PREREQUISITES: ENSURE THE INDEXING POLICY INCLUDE SPATIAL INDEXING

If your spatial queries does not work, check that spatial indexing is enabled.

In the “Settings” for your container, check that the Indexing Policy include your location GeoJSON as a spatial point. My field is called “location”, yours can be named differently:

Spatial Indexing Enabled
Spatial Indexing Enabled

STEP 1: CREATE A MODEL FOR THE COSMOSDB DOCUMENT

This is not specific for the CosmosDB location search, but generally, you need to map the JSON document in CosmosDB to a C# model. This is a simplified version of mine. Yours will look different.

using Newtonsoft.Json;
using System.Text.Json.Serialization;

namespace MyCode
{
  public class BeautifulWorldModel
  {
    [JsonPropertyName("panoId")]
    public string PanoId { get; set; }

    [JsonProperty("location")]
    [JsonPropertyName("location")]
    public Location Location { get; set; }
  }

  public class Location
  {
    [JsonProperty("type")]
    [JsonPropertyName("type")]
    public string? Type { get; set; }

    [JsonProperty("coordinates")]
    [JsonPropertyName("coordinates")]
    public double[] Coordinates { get; set; }
  }
}

NOTE: Both System.Text.Json and NewtonSoft.Json is required for CosmosDB operations in C#. The Microsoft.Azure.Cosmos NuGet package is dependent on NewtonSoft.Json (as per 2025-06-17). This will change in the future.

STEP 2: PERFORM THE COSMOSDB LOCATION SEARCH

The geobased search is straight forward, as you query CosmosDB like any other query. Granularity is in meters. The search look like this:

SELECT * FROM c
WHERE ST_DISTANCE(c.location, {
  "type": "Point",
  "coordinates": [12.5757, 55.6796]
}) < 100

This search returns any document with a location within 100 meters from the provided coordinates.

An example repository look like this:

using Microsoft.Azure.Cosmos;

namespace MyCode
{
  public class BeautifulWorldRepository
  {
    private Container _container;

    public BeautifulWorldRepository()
    {
      CosmosClient cosmosClient = new CosmosClient("YOUR_COSMOSDB_URL", "YOUR_COSMOSDB_KEY");
      _container = cosmosClient.GetContainer(
        "YOUR_COSMOSDB_DATABASE", 
        "YOUR_COSMOSDB_CONTAINER");
    }

    public async Task<IEnumerable<BeautifulWorldModel>> GetByLocationAsync(double longitude, double latitude, int distanceInMeters)
    {
      var query = new QueryDefinition("SELECT * FROM c WHERE ST_DISTANCE(c.location, {\"type\": \"Point\", \"coordinates\": [@longitude, @latitude]}) < @distance")
        .WithParameter("@longitude", longitude)
        .WithParameter("@latitude", latitude)
        .WithParameter("@distance", distanceInMeters);
      FeedIterator<BeautifulWorldModel> resultSet = _container.GetItemQueryIterator<BeautifulWorldModel>(query);
      List<BeautifulWorldModel> results = new List<BeautifulWorldModel>();
      while (resultSet.HasMoreResults)
      {
        foreach (var item in await resultSet.ReadNextAsync())
        {
          results.Add(item);
        }
      }
      return results;
    }
  }
}

PERFORM LOCATION SEARCH WITHIN A RECTANGLE

The search query for searching within a rectangle is slightly more complex. You must add 5 points to your rectangle, and you must add them COUNTER CLOCKWISE. Adding them clockwise will return all locations.

You add the 4 corners of the rectangle, and then you close the box by adding the first corner again. This creates a closed box that the search will perform within.

This is an example of an approximated box within France:

SELECT *
FROM c
WHERE ST_WITHIN(c.location, {
  "type": "Polygon",
  "coordinates": [[
    [-5.0, 42.0],   -- Southwest corner (near Bay of Biscay)
    [8.5, 42.0],    -- Southeast corner (near Mediterranean)
    [8.5, 51.5],    -- Northeast corner (near Belgium/Luxembourg)
    [-5.0, 51.5],   -- Northwest corner (near English Channel)
    [-5.0, 42.0]    -- Closing the polygon
  ]]
})

Notice how the coordinates are in counter clockwise order. Reversing the order will make the search fail.

That’s it. You are now a CosmosDB and spatial search expert. Happy coding.

MORE TO READ:


Viewing all articles
Browse latest Browse all 286

Trending Articles