let's say we have a bunch of art galleries stored in mongodb located in paris and we want to retrieve only those that are within 20 kilometers of the eiffel tower.
mongodb makes it extremely easy if you store the entities properly tagged with their longitudes and latitudes.
Getting Started
if you haven't already, please see the introductory article mentioned below in order to get a new project setup before continuing with the rest of this article.
Define The Gallery Entity
public class ArtGallery : Entity
{
public string Name { get; set; }
public Coordinates2D Location { get; set; }
}
the Coordinates2D
type is a special class supplied by the library to streamline the storage & retrieval of geographical data.
Create Some Entities
await new[]
{
new ArtGallery {
Name = "Galleria Le-Pari",
Location = new Coordinates2D(48.8539241, 2.2913515)
},
new ArtGallery {
Name = "Versailles House Of Art",
Location = new Coordinates2D(48.796964, 2.137456)
},
new ArtGallery {
Name = "Poissy Arts & Crafts",
Location = new Coordinates2D(48.928860, 2.046889)
}
}.SaveAsync();
we are setting the locations of these galleries by creating new instances of Coordinates2D
class supplying the longitude and latitude to the constructor. finally the whole array is persisted to mongodb by calling the .SaveAsync()
extension method which issues a bulk write command.
Create An Index
mongodb geospatial queries require an index to be created which can be easily done as follows:
await DB.Index<ArtGallery>()
.Key(g => g.Location, KeyType.Geo2DSphere)
.Option(o => o.Background = false)
.CreateAsync();
we specify the index key as the Location
property of the ArtGallery class and type of key as Geo2DSphere
. also we are telling mongodb to build the index in the foreground with the .Option()
method.
Do The Search
var locEiffelTower = new Coordinates2D(48.857908, 2.295243);
var results = await DB.Find<ArtGallery>()
.Match(g => g.Location, locEiffelTower, 20000)
.ExecuteAsync();
foreach (var gallery in results)
{
Console.WriteLine(gallery.Name);
}
Console.Read();
first we define the search point, which in this case is the location/coordinates of the eiffel tower in paris.
then we issue a find command that has the following matching criteria/arguments:
- the property where coordinates are stored on the ArtGallery entity.
- the search point to base the matching on.
- how far away from the search point (in meters) - at maximum should matches be located in.
The End Result
after running the find command you will see the following output in the console window:
Galleria Le-Pari
Versailles House Of Art
notice that Poissy Arts & Crafts
has been excluded. that is because it is located further than 20KMs from the eiffel tower.
Getting Distances Back
if you need to also retrieve how far away each gallery is from the eiffel tower, simply do the following:
add the following import:
using MongoDB.Driver;
add another property to the ArtGallery
entity like so:
public double DistanceInMeters { get; set; }
query mongodb with the IAggregateFluent
interface like so:
var results = await DB.FluentGeoNear<ArtGallery>(
NearCoordinates: locEiffelTower,
DistanceField: g => g.DistanceInMeters,
MaxDistance: 20000)
.ToListAsync();
write to the console like so:
foreach (var gallery in results)
{
Console.WriteLine(
$"{gallery.Name} - {(gallery.DistanceInMeters / 1000).ToString("00.00")} KM");
}
Next Steps...
if the above exercise has piqued your interest enough to discover how to easily get things done with mongodb using c#, please visit the official website of MongoDB.Entities. you can also check out the source code on github:
dj-nitehawk / MongoDB.Entities
A data access library for MongoDB with an elegant api, LINQ support and built-in entity relationship management
MongoDB.Entities
A light-weight .net standard library with barely any overhead that aims to simplify access to mongodb by abstracting the official driver while adding useful features on top of it resulting in an elegant API surface which produces beautiful, human friendly data access code.
More Info:
please visit the official website for detailed documentation:
Top comments (3)
First of all, thank you for this library, I appreciate your work greatly.
I had to add the IndexKey to get things working with CosmosDB.
Code along the lines of this tutorial that works for me using CosmoDB with Driver 4.2:
Hi, I implemented all the steps but the final result is Zero, I use the exact same coordinates that the example and I get zero results, do you know what can I be missing?
i just copy/pasted the above code into a new console project and it works fine. here's a gist if you wanna try again. the only thing i had to add was the connection initialization.