Performing Geospatial Calculations with Azure CosmosDB
Azure CosmosDB is a multi-model, globally distributed database, as well as a geospatial calculation powerhouse. It can calculate the distance between two points, determine whether a road runs through a city, and identify if a body of water is wholly contained within a state. In this article, you’ll learn how to unleash the potential of Azure CosmosDB so your apps can handle geographic data on a cosmic scale!
We’ll walk through the process of adding geospatial calculations to an app that will be able to determine features contained within a boundary, what features intersect with each other, and the distance features are from a single point.
For this post, Madison Wisconsin USA will be the location data is pulled from.
What is Geospatial Data?
Spatial data describes the position and shape of objects in space. In most apps, we’re interested in locations on Earth: the location of a landmark, the route of a road, or the boundaries of a city. This geographical, or geospatial, data can be described by using three different types of data: Points, Line Strings, and Polygons.
- A Point models a single longitude and latitude location; a landmark or a person’s location, for example.
- A Line String models several points with the lines used to connect those points, such as the path of a highway or a river.
- Finally, a Polygon is a boundary of connected points whose Line Strings form a closed loop. The boundaries of a city or that of a body of water are examples of Polygons.
There are three operations you can perform with this geospatial data. Distance, Intersects, and Within.
- Distance determines how far away two geospatial objects are away from each other.
- Intersects indicates whether part of one object lies within the other.
- Within determines whether one object wholly contains another within its boundaries.
Now that you know what geospatial data is and the operations you can perform with it, let’s see how to work with it in your Xamarin apps!
Working With Geospatial Data
If you don’t already know how to work with CosmosDB, check out this excellent documentation on working with CosmosDB and Xamarin apps.
Xamarin apps accesses CosmosDB with the Microsoft.Azure.DocumentDB NuGet package (the DocumentDB refers to one of the underlying databases that CosmosDB supports). The NuGet package contains several classes that model the geospatial types mentioned above, and the classes contain helper methods which perform the various operations on geospatial data.
The app we’re building works with the following geospatial features:
There are polygons to represent the entire state of Wisconsin, the city of Madison, the city of Milwaukee, and the city of Chicago. Line strings represent major highways. Finally, there’s a single point to represent the location of an annual Cheese Curd Festival (because it’s Wisconsin and they love cheese! 🧀). Each of these locations will be referred to as features. You can view this in CosmosDB by clicking here.
By picking a feature, and then a spatial operation, you’re able to determine which highways and cities intersect each other, or which cities contain which highways, or even how far a city is away from the Cheese Festival (very important)! There are many combinations of what one can do.
Selecting a Feature
The first thing the app needs to do is select a feature. It does so with the following code:
// collectionURI is a URI pointing to the CosmosDB collection
var featureQuery = client.CreateDocumentQuery<Feature>(collectionUri)
.Where(f => f.LocationName == featureName)
This is a common CosmosDB query for finding a document and follows the documentation closely. From here on out, the returned document will be used in the other operations as the feature to compare against.
Finding the Distance
Let’s start with the most important question, the distance of the features to the Cheese Curd Festival!
// cheeseFestival is a Point
var distanceQuery = client.CreateDocumentQuery<Feature>(collectionUri)
.Where(f => f.Id == feature.Id) // feature is what you want to find out how far away it is
.Select(f => cheeseFestival.Distance(f.Location)) // Location is a Geometry type
That’s it! The base class for all geospatial objects,
Microsoft.Azure.Documents.Spatial.Geometry contains a
Distance function which will tell CosmosDB to figure out the distances between all the various geometries and the point/return that as a
Pull the results from the DocumentQuery exactly as you normally would.
The following code finds everything in the database that crosses paths or intersects with the passed-in
var intersectingQuery = client.CreateDocumentQuery<Feature>(collectionUri)
.Where(f => feature.Id != f.Id) // Ignore passed in
.Where(f => feature.Location.Intersects(f.Location))
That’s all there is to it! This will find everything in the database that intersects with the passed in feature.
Finding Features Contained Within
By now, you may be able to guess how this is done. There’s a
Within function that determines which objects are wholly contained within another. The code looks like this:
var withinQuery = client.CreateDocumentQuery<Feature>(collectionUri)
.Where(f => feature.Id != f.Id) // Ignore passed in
.Where(f => f.Location.Within(feature.Location))
The best part? These queries return lightning fast, even though there are many points, line strings, and polygons being queried!
You can view the full code for this sample here. There’s also ample documentation for spatial operation in Azure CosmosDB on docs.microsoft.com, and a recently completed app that makes use of CosmosDB’s spatial features plus a number of other Azure offerings here.
The best thing to do, though, is trying it for yourself! Create a free Azure account (with enough credit to use CosmosDB for a year!), set up a CosmosDB instance, and start creating your own spatially aware database today!
Have questions or comments about this post? Chat about it in the Xamarin Forums.