简体   繁体   中英

How to store and query an array of coordinates in C# Mongodb strongly typed driver

I am using the official C# MongoDb strongly typed driver version 2.5.0 to interact with MongoDB.

I have an array of longitude and latitude coordinates and I want to store them in the MongoDB.

What is the name of the class used to store an array of coordinates? So I can lately do the following query, check If a given coordinate is near any point in the array of coordinates, how to achieve this?

Here is a simple code that demonstrate the question.

        var coordinates = new List<(double latitude, double longitude)>();

        //Store coordinates array in the database

        (double latitude, double longitude) point = (-33.847927, 150.6517805);

        int maxDistance = 300;//Max Distance in meters

        //Check if any point in the coordinates array is 300 m near the given point

Edit:-

According to this question mentioned in @CodeFuller comment below:-

MongoDB geospatial index on an array (multikey + geospatial)

MongoDB doesn't support geospatial index on arrays, so consider the following classes:

class SomeDocument {

    public ObjectId Id { get; set; }

    public string Title { get; set; }

    public List<MyClass> Locations {get; set;} = new List<MyClass>();
}

class MyClass {

    public ObjectId Id { get; set; }

    public GeoJsonPoint<GeoJson2DGeographicCoordinates> Location { get; set; 

}

How to get all instances of SomeDocument that at least have one point near a given point? And sort them by the nearest one?

MongoDB .NET Driver provides MongoDB.Driver.GeoJsonObjectModel.GeoJson2DGeographicCoordinates class for 2D geographic coordinates.

Here is basic usage:

  1. In model class define the property with GeoJsonPoint<GeoJson2DGeographicCoordinates> type:

     public class SomeDocument { public ObjectId Id { get; set; } public string Title { get; set; } public GeoJsonPoint<GeoJson2DGeographicCoordinates> Location { get; set; } }
  2. Make sure you have 2dsphere (or 2d , depends on your needs) index for Location field. You could create and index via mongo client:

    db.testCollection.createIndex( { Location : "2dsphere" } );

    Or via MongoDB .NET Driver:

     var database = mongoClient.GetDatabase("testDB"); IMongoCollection<SomeDocument> collection = database.GetCollection<SomeDocument>("testCollection"); collection.Indexes.CreateOne(new IndexKeysDefinitionBuilder<SomeDocument>().Geo2DSphere(x => x.Location));
  3. Inserting data:

     collection.InsertOne(new SomeDocument { Title = "Place #1", Location = GeoJson.Point(new GeoJson2DGeographicCoordinates(145.89, -35.83)), }); collection.InsertOne(new SomeDocument { Title = "Place #2", Location = GeoJson.Point(new GeoJson2DGeographicCoordinates(154.98, -53.38)), });

    Note that in MongoDB you specify longtitude first .

  4. Finding the neighbors:

     var point = GeoJson.Point(new GeoJson2DGeographicCoordinates(145.889, -35.831)); int maxDistance = 300; IAsyncCursor<SomeDocument> cursor = collection.FindSync(new FilterDefinitionBuilder<SomeDocument>().Near(x => x.Location, point, maxDistance: maxDistance)); // Check whether at least one is near the point var hasNeighbors = cursor.Any();

Sample Project on GitHub

Updates to @CodeFuller's answer.

Point 2.

CreateOne( new IndexKeysDefinitionBuilder..) is depreciated. Instead use CreateOne( new CreateIndexModel()... .

Here's how:

collection.Indexes.CreateOne(
                new CreateIndexModel<TDocument>(
                    new IndexKeysDefinitionBuilder<TDocument>().Geo2DSphere(x => x.Location)));

Later I created a Generic function to created indexes on startup like this:

public CreateIndexes CreateGeoSpatialIndex<TDocument>(Expression<Func<TDocument, object>> field, string collectionName)
    {
        var collection = _database.GetCollection<TDocument>(collectionName);

        try
        {
            collection.Indexes.CreateOne(
                new CreateIndexModel<TDocument>(
                    new IndexKeysDefinitionBuilder<TDocument>().Geo2DSphere(field)));
        }
        catch (Exception ex) when (ex.Message.Contains("already exists"))
        {
            // Log info
        }

        return this;
    }

Point 4.

Also, Near() didn't work for me, instead, had to use NearSphere() while querying.

var filterDefinition = new FilterDefinitionBuilder<T>().NearSphere(x => x.Location, lng, lat, maxdistance)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM