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

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

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

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

用于存储坐标数组的 class 的名称是什么?所以我最近可以做以下查询,检查给定坐标是否在坐标数组中的任何点附近,如何实现?

这是演示问题的简单代码。

        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 不支持数组的地理空间索引,因此请考虑以下 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; 

}

如何获取至少有一个点靠近给定点的所有 SomeDocument 实例?并按最近的排序?

MongoDB .NET 驱动程序提供 MongoDB.Driver.GeoJsonObjectModel.GeoJson2DGeographicCoordinates class 二维地理坐标。

基本用法如下:

  1. 在模型 class 中用 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 client:

    创建和索引

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

    或通过 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 你 .

  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();
    

Sample Project on GitHub

更新@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)