【问题标题】:How do I use a geospatial query in the 2.1 MongoDB C# driver?如何在 2.1 MongoDB C# 驱动程序中使用地理空间查询?
【发布时间】:2015-11-29 18:08:31
【问题描述】:

这几天我一直在努力解决这个问题。我尝试在 C# 中运行一个非常简单的查询,它在 shell 中看起来像这样。

db.runCommand({geoNear: "items", near: {type: "Point", coordinates : [-111.283344899999, 47.4941836]}, spherical : true, distanceMultiplier: 3963.2, maxDistance : 25});

我的收藏是这样的

{    
  "_id" : ObjectId(),    
  "Title" : "arst",    
  "Description" : "<p>arst</p>",    
  "Date" : new Date("11/29/2015 09:28:15"),    
  "Location" : {    
    "type" : "Point",    
    "Coordinates" : [-111.28334489999998, 47.4941836]    
  },    
  "Zip" : "59405"    
}

根据MongoDB C# API Docs 此处的文档,MongoDB.Driver.Builders.Query 对象现在是旧的。所以当我做这样的事情时

 var point = new GeoJson2DGeographicCoordinates(double.Parse(longitude), double.Parse(latitude)) ;
        var query = Query<Item>.Near(x => x.Location, new GeoJsonPoint<GeoJson2DGeographicCoordinates>(point), distance, true);

        var result = collection.Find(query);

编译器抱怨它无法从 IMongoQuery 转换为 FilterDefinition。这告诉我新的 2.1 库不支持旧版 Query 构建器。但是对于我的一生,我在引用替代品的 api 文档中找不到任何地方?

谁能指出我在 2.1 C# 驱动程序中执行这个简单的地理空间查询的正确方向?我被难住了。

另外,我确实在集合上创建了一个 2dsphere 索引,如果我不这样做,shell 命令将无法工作。这是索引输出。

{
            "v" : 1,
            "key" : {
                    "Location.Coordinates" : "2dsphere"
            },
            "name" : "Location.Coordinates_2dsphere",
            "ns" : "ppn.items",
            "2dsphereIndexVersion" : 2
    }

编辑

在翻阅了大量文档后,我想我找到了。所有示例仍然显示旧的 Query 方法,但新方法似乎是 Builders.Filter 命名空间的一部分。所以这个代码块似乎对我有用,

 double lng = double.Parse(longitude);
 double lat = double.Parse(latitude);
 point = new GeoJson2DGeographicCoordinates(lng, lat);
 pnt = new GeoJsonPoint<GeoJson2DGeographicCoordinates>(point);
 dis = distance * 1609.34;
 fil = Builders<Item>.Filter.NearSphere(p => p.Location.Coordinates, pnt, dis);

 filter = filter & fil;

 var sort = Builders<Item>.Sort.Descending("Date");

 // This is the actual query execution
 List<Item> items = collection.Find(filter).Sort(sort).ToListAsync().Result;

这个代码块非常混乱,它是反复尝试和失败的结果。我相信我会想办法清理它。对我来说,您必须从 GeoJson2DGeographicCoordinates 创建一个 GeoJsonPoint 似乎有点冗长,但我相信这是有充分理由的。如果有人知道,请随时发表评论。非常欢迎任何有关改进此答案的建议,这是对文档的令人沮丧的挖掘,因此希望这有助于为其他人指明正确的方向。

【问题讨论】:

    标签: c# mongodb geospatial spatial


    【解决方案1】:

    这就是我最终的做法:

        public IQueryable<TEntity> FindNear<TEntity>(string collectionName, Expression<Func<TEntity, object>> field, double longitude, double latitude, double maxDistanceInKm) where TEntity : IEntity
        {
            var collection = database.GetCollection<TEntity>(collectionName);
            var point = GeoJson.Point(GeoJson.Geographic(longitude, latitude));
            var filter = Builders<TEntity>.Filter.Near(field, point, maxDistanceInKm * 1000);
            return collection.Find(filter).ToList().AsQueryable();
        }
    

    【讨论】:

      【解决方案2】:

      这是对任何感兴趣的人进行地理空间聚合查询的最便捷方式:

      using MongoDB.Driver;
      using MongoDB.Entities;
      using System;
      
      namespace StackOverflow
      {
          public class Program
          {
              public class Place : Entity
              {
                  public string Name { get; set; }
                  public DateTime Date { get; set; }
                  public Coordinates2D Location { get; set; }
                  public double DistanceMeters { get; set; }
              }
      
              static void Main(string[] args)
              {
                  //connect to mongodb
                  new DB("test");
      
                  //create a geo2dsphere index
                  DB.Index<Place>()
                    .Key(x => x.Location, KeyType.Geo2DSphere)
                    .Option(x => x.Background = false)
                    .Create();
      
                  //create and save a place
                  var paris = new Place
                  {
                      Name = "paris",
                      Location = new Coordinates2D(48.8539241, 2.2913515),
                      Date = DateTime.UtcNow
                  };
                  paris.Save();
      
                  var eiffelTower = new Coordinates2D(48.857908, 2.295243);
      
                  //find all places within 1km of eiffel tower.
                  var places = DB.GeoNear<Place>(
                                    NearCoordinates: eiffelTower,
                                    DistanceField: x => x.DistanceMeters,
                                    MaxDistance: 1000)
                                 .SortByDescending(x=>x.Date)
                                 .ToList();
              }
          }
      }
      

      它生成以下聚合管道:

      {
                      "$geoNear": {
                          "near": {
                              "type": "Point",
                              "coordinates": [
                                  48.857908,
                                  2.295243
                              ]
                          },
                          "distanceField": "DistanceMeters",
                          "spherical": true,
                          "maxDistance": NumberInt("1000")
                      }
                  },
                  {
                      "$sort": {
                          "Date": NumberInt("-1")
                      }
                  }
      

      以上是使用MongoDB.Entities 便利库完成的,我是该库的作者。

      【讨论】:

        【解决方案3】:

        这就是我的做法。它非常简单,并且能够将您的查询从 mongo shell 复制并粘贴到查询变量中。

        对于简单的查找,如果在 100 米范围内,则返回 1 个文档:

        var nearSphereQuery = "{location: { $nearSphere: {$geometry: { type: \"Point\", coordinates: [-1.50,53.50]},  $maxDistance: 100}} }";
        var nearSphereBsonDoc = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>(nearSphereQuery);
        var result = points.Find(nearSphereBsonDoc).Limit(1).SingleOrDefault();
        if (result != null) {
            // do stuff here
        } else {
            // nothing found
        }
        

        要获取相同请求的搜索点的距离:

        var geoNearQuery = "{$geoNear: { near: { type: \"Point\", coordinates: [-1.50, 53.50]}, spherical: true, distanceField: \"distance\"} } ,{$match: { distance: { $lt: 100} } }";
        var geoNearBsonDoc = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>(geoNearQuery);
        var pipeline = new List<BsonDocument>();
        var matchQuery = "{ $match: { distance: { $lt: 10} } }";
        var matchBsonDoc = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>(matchQuery);
        var pipeline = new List<BsonDocument>();
        pipeline.Add(geoNearBsonDoc);
        pipeline.Add(matchBsonDoc);   
        pipeline.Add(new BsonDocument { { "$limit", 1 } });
        var result = points.Aggregate<BsonDocument>(pipeline).SingleOrDefault();
        if (result != null) {
            Double dist = Convert.ToDouble(result["distance"]);
        } else {
            // nothing found
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-04
          • 1970-01-01
          • 2019-03-01
          • 2020-04-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多