You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C# MongoDB强类型驱动:坐标数组存储及附近点查询实现

C# MongoDB驱动2.5.0:经纬度数组存储与附近点查询方案

嘿,我来帮你搞定这个地理空间相关的问题,刚好对2.5.0版本的官方驱动熟门熟路~

一、存储坐标数组的强类型类

在这个版本的驱动里,你需要用**GeoJsonPoint<GeoJson2DGeographicCoordinates>**来表示单个经纬度坐标,而坐标数组直接用List<GeoJsonPoint<GeoJson2DGeographicCoordinates>>(或者你习惯的其他集合类型,比如IEnumerable)就行。

这里要敲个重点:MongoDB的地理空间规范是先经度(longitude),后纬度(latitude),创建坐标的时候可别搞反顺序,不然查出来的位置会跑偏!

给你写个实体类的例子,一目了然:

using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver.GeoJsonObjectModel;

public class LocationRecord
{
    [BsonId]
    public ObjectId Id { get; set; }

    // 用来存坐标数组的属性
    [BsonElement("coords")]
    public List<GeoJsonPoint<GeoJson2DGeographicCoordinates>> Coordinates { get; set; }
}

要是你偏好更简洁的数值数组(比如List<double[]>),也能行,但得加BsonRepresentation标记让MongoDB识别成地理空间类型。不过还是更推荐用强类型的GeoJsonPoint,驱动会自动帮你处理序列化和类型识别,少踩坑。

二、实现「检查给定坐标是否靠近数组内任意点」的查询

这个需求得靠MongoDB的地理空间查询运算符来实现,结合C#驱动的查询语法很容易搞定,步骤如下:

1. 先构建目标坐标

还是要记住「经度在前,纬度在后」:

// 举个例子:要检查的目标坐标(纬度31.23,经度121.47)
var targetLocation = GeoJson.Point(new GeoJson2DGeographicCoordinates(121.47, 31.23));

2. 编写查询条件

我们要找的是文档中Coordinates数组里,有任意一个点在目标坐标的指定范围内(比如1000米内)。这里用ElemMatch结合WithinSphere就很合适:

var filter = Builders<LocationRecord>.Filter.ElemMatch(
    doc => doc.Coordinates,
    point => point.WithinSphere(targetLocation, 1000) // 1000是距离,单位米
);

或者用更直观的AnyNear方法也能达到同样效果:

var filter = Builders<LocationRecord>.Filter.AnyNear(
    doc => doc.Coordinates, 
    targetLocation, 
    maxDistance: 1000
);

3. 执行查询并判断结果

最后执行查询,看看有没有符合条件的文档就行:

// 先获取集合实例
var locationCollection = mongoDb.GetCollection<LocationRecord>("your_collection_name");
// 判断是否存在匹配的文档
var hasNearbyPoint = locationCollection.Find(filter).Any();

if (hasNearbyPoint)
{
    Console.WriteLine("找到了靠近目标坐标的点!");
}
else
{
    Console.WriteLine("没有找到符合条件的点");
}

必看注意事项

  • 一定要给Coordinates字段创建地理空间索引!不然数据量大的时候查询速度会慢到离谱。创建索引的代码给你准备好了:
var geoIndex = new CreateIndexModel<LocationRecord>(
    Builders<LocationRecord>.IndexKeys.Geo2DSphere(doc => doc.Coordinates)
);
locationCollection.Indexes.CreateOne(geoIndex);
  • 距离参数默认单位是米,如果要用千米的话,把数值换算成米传入即可(比如5千米就传5000)。

内容的提问来源于stack exchange,提问作者Waxren

火山引擎 最新活动