如何在 2.1 MongoDB C# 驱动程序中使用地理空间查询?
Posted
技术标签:
【中文标题】如何在 2.1 MongoDB C# 驱动程序中使用地理空间查询?【英文标题】:How do I use a geospatial query in the 2.1 MongoDB C# driver? 【发布时间】: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 似乎有点冗长,但我相信这是有充分理由的。如果有人知道,请随时发表评论。非常欢迎任何有关改进此答案的建议,这是对文档的令人沮丧的挖掘,因此希望这有助于为其他人指明正确的方向。
【问题讨论】:
【参考方案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 ***
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
【讨论】:
以上是关于如何在 2.1 MongoDB C# 驱动程序中使用地理空间查询?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Visual Studio 2012 中使一个类完全静态,这样它就不会出现任何错误? - C# [关闭]