如何在C#Mongodb强类型驱动程序中存储和查询坐标数组

时间:2018-04-11 15:46:43

标签: c# .net mongodb mongodb-query mongodb-.net-driver

我正在使用官方C#MongoDb强类型驱动程序版本2.5.0与MongoDB进行交互。

我有一个经度和纬度坐标数组,我想将它们存储在MongoDB中。

用于存储坐标数组的类的名称是什么?所以我最近可以做以下查询,检查如果一个给定的坐标靠近坐标数组中的任何一点,如何实现呢?

这是一个展示问题的简单代码。

        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

修改: -

根据以下@CodeFuller评论中提到的这个问题: -

MongoDB geospatial index on an array (multikey + geospatial)

MongoDB不支持数组上的地理空间索引,因此请考虑以下类:

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; 

}

如何让SomeDocument的所有实例至少在给定点附近有一个点?并按最近的一个排序?

2 个答案:

答案 0 :(得分:3)

MongoDB .NET驱动程序为2D地理坐标提供MongoDB.Driver.GeoJsonObjectModel.GeoJson2DGeographicCoordinates类。

以下是基本用法:

  1. 在模型类中,使用GeoJsonPoint<GeoJson2DGeographicCoordinates>类型定义属性:

    public class SomeDocument
    {
        public ObjectId Id { get; set; }
    
        public string Title { get; set; }
    
        public GeoJsonPoint<GeoJson2DGeographicCoordinates> Location { get; set; }
    }
    
  2. 确保2dsphere字段的2d(或Location,取决于您的需求)索引。您可以通过mongo客户端创建和索引:

      

    db.testCollection.createIndex({Location:&#34; 2dsphere&#34;});

    或通过MongoDB .NET驱动程序:

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

    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)),
    });
    

    请注意,在MongoDB中,您specify longtitude first

  4. 寻找邻居:

    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();
    
  5. Sample Project on GitHub

答案 1 :(得分:0)

更新为@CodeFuller的答案。

第2点。

CreateOne( new IndexKeysDefinitionBuilder..)已贬值。而是使用CreateOne( new CreateIndexModel()...

方法如下:

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

稍后,我创建了一个通用函数来在启动时创建索引,如下所示:

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;
    }

第4点。

此外,Near()对我不起作用,而是在查询时必须使用NearSphere()。

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