天天看点

Asp.Net Core MongoDB 空间定位(点)与距离检索

作者:CShap新势力

一:我们先准备点数据

采用高德坐标系来拾取点数 (https://lbs.amap.com/tools/picker)

注意:要注册成开发者,否则拾取到的经纬度只精确到2位

第一百货 119.647437,29.083693
欧景名城 119.639798,29.080843
金华网络经济中心 119.644604,29.074617
金华市第十五中学 119.652758,29.075029
金磐医院 119.642716,29.072554
龙腾江南建材市场 119.636579,29.072366
宝莲广场 119.644433,29.079568
新世纪大厦 119.655548,29.08088
泰地世璟园 119.658809,29.073379
美兰湖公馆 119.639497,29.06824
西京大厦 119.63645,29.081855
星月花园 119.635592,29.078292
兰溪街商业步行街 119.649325,29.082606
阳光城市花园 119.666963,29.082456
华园小区 119.666491,29.073604
印象城 119.658509,29.070716           
Asp.Net Core MongoDB 空间定位(点)与距离检索

地理位置

二:把数据存到mongodb中,便于后面使用

db.mapinfo.insert({"address": "第一百货", "name":"第一百货", "location": {"type": "Point", "coordinates": [119.647437,29.083693]}})
db.mapinfo.insert({"address": "欧景名城", "name":"欧景名城", "location": {"type": "Point", "coordinates": [119.639798,29.080843]}})
db.mapinfo.insert({"address": "金华网络经济中心", "name":"金华网络经济中心", "location": {"type": "Point", "coordinates": [119.644604,29.074617]}})
db.mapinfo.insert({"address": "金华市第十五中学", "name":"金华市第十五中学", "location": {"type": "Point", "coordinates": [119.652758,29.075029]}})
db.mapinfo.insert({"address": "金磐医院", "name":"金磐医院", "location": {"type": "Point", "coordinates": [119.642716,29.072554]}})
db.mapinfo.insert({"address": "龙腾江南建材市场", "name":"龙腾江南建材市场", "location": {"type": "Point", "coordinates": [119.636579,29.072366]}})
db.mapinfo.insert({"address": "宝莲广场", "name":"宝莲广场", "location": {"type": "Point", "coordinates": [119.644433,29.079568]}})
db.mapinfo.insert({"address": "新世纪大厦", "name":"新世纪大厦", "location": {"type": "Point", "coordinates": [119.655548,29.08088]}})
db.mapinfo.insert({"address": "泰地世璟园", "name":"泰地世璟园", "location": {"type": "Point", "coordinates": [119.658809,29.073379]}})
db.mapinfo.insert({"address": "美兰湖公馆", "name":"美兰湖公馆", "location": {"type": "Point", "coordinates": [119.639497,29.06824]}})
db.mapinfo.insert({"address": "西京大厦", "name":"西京大厦", "location": {"type": "Point", "coordinates": [119.63645,29.081855]}})
db.mapinfo.insert({"address": "星月花园", "name":"星月花园", "location": {"type": "Point", "coordinates": [119.635592,29.078292]}})
db.mapinfo.insert({"address": "兰溪街商业步行街", "name":"兰溪街商业步行街", "location": {"type": "Point", "coordinates": [119.649325,29.082606]}})
db.mapinfo.insert({"address": "阳光城市花园", "name":"阳光城市花园", "location": {"type": "Point", "coordinates": [119.666963,29.082456]}})
db.mapinfo.insert({"address": "华园小区", "name":"华园小区", "location": {"type": "Point", "coordinates": [119.666491,29.073604]}})
db.mapinfo.insert({"address": "印象城", "name":"印象城", "location": {"type": "Point", "coordinates": [119.658509,29.070716]}})           

一定要加索引

mongodb 提供的地图索引有两种,分别是 2d 和 2dsphere。

2d 索引通过二维平面记录点坐标,支持在平面几何中计算距离,而 2dsphere 则支持在球面上进行距离的计算,并且支持 mongodb 的所有地理空间查询方法。

简单的理解,2dsphere 是 2d 的增强版。根据官方推荐,如果你的mongodb版本大于2.6

db.mapinfo.ensureIndex({location : "2dsphere"})           
Asp.Net Core MongoDB 空间定位(点)与距离检索

数据库数据

假设当前位置在“1921文化创意园” 具体坐标 119.627438,29.078988

Asp.Net Core MongoDB 空间定位(点)与距离检索

当前位置

检索规定半径以内数据(单位为米)

这里取2000米

db.mapinfo.find({location: {$near: {$geometry: {type: "Point", coordinates: [119.627438,29.078988]}, $maxDistance: 2000}}})           

或者

db.mapinfo.find({location: {$nearSphere: {$geometry: {type: "Point", coordinates: [119.627438,29.078988]}, $maxDistance: 2000}}})           
Asp.Net Core MongoDB 空间定位(点)与距离检索

查询结果,由近到远

按照离我最近排序,除了使用 $nearSphere 查询外,我们还可以使用 aggregate 来实现。

使用 aggregate 有两个好处。

1.我们在进行排序的后,可以返回两点之间的距离。

2.我们可以进行更为复杂的排序,例如我们可以先根据某个字段进行排序,然后该字段相同的情况下再根据距离排序。

db.mapinfo.aggregate([
   {
     $geoNear: {
        near: {type: "Point", coordinates: [119.627438,29.078988]},
        distanceField: "distance",
        spherical: true,       
        maxDistance: 15000,
				query: {
			    address: {$regex:'建材'}
				}
     }
   },
   { $skip: 0 },
   { $limit: 2 }
])           
Asp.Net Core MongoDB 空间定位(点)与距离检索

aggregate 查询

如果我们希望查询以某个点为中心的圆几公里以内的数据,那你可以如下操作:

地球表面1弧度距离约为6378137米, 0.001弧度距离为6378米

db.mapinfo.find({
    "location": {
        "$geoWithin": {
            "$centerSphere": [
                [
                    119.627438,29.078988
                ],
                0.025 // 单位为弧度
            ]
        }
    }
})           
Asp.Net Core MongoDB 空间定位(点)与距离检索

以某个点为中心的圆几公里以内的数据

写到这里,其实已经实现了基于MongoDB 空间定位(点)与距离检索

那.net中代码如何实现,看下面具体说明。

编写实体对象 mapinfo

public class mapinfo
    {
        /// <summary>
        /// 主键
        /// </summary>
        [BsonId]
        [BsonRepresentation(BsonType.ObjectId)]
        public string id { get; set; }

        /// <summary>
        /// 地址
        /// </summary>
        public string address { get; set; }
        /// <summary>
        /// 社区名称
        /// </summary>
        public string name { get; set; }

        /// <summary>
        /// 距离
        /// </summary>
        public double? distance { get; set; }

        /// <summary>
        /// 经纬度坐标
        /// </summary>
        public GeoJsonPoint<GeoJson2DGeographicCoordinates> location { get; set; }
    }           

IMapinfoMongoRepository

public interface IMapinfoMongoRepository
    {
        public List<Models.MongoEnity.mapinfo> QueryNear(string keywords,int pageIndex, int pageSize, double longitude, double latitude, int maxDistance);
    }           

MapinfoMongoRepository

public class MapinfoMongoRepository : IMapinfoMongoRepository
    {
        private readonly ILogger<MapinfoMongoRepository> _logger;
        private readonly IMongoDbGenericHelper<Models.MongoEnity.mapinfo> _mapinfoHelper;
        public MapinfoMongoRepository(ILogger<MapinfoMongoRepository> logger, IMongoDbGenericHelper<Models.MongoEnity.mapinfo> mapinfoHelper)
        {
            _logger = logger;
            _mapinfoHelper = mapinfoHelper;
        }

        /// <summary>
        /// 查询附近的信息
        /// </summary>
        /// <param name="keywords"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="longitude"></param>
        /// <param name="latitude"></param>
        /// <param name="maxDistance"></param>
        /// <returns></returns>
        public List<Models.MongoEnity.mapinfo> QueryNear(string keywords, int pageIndex, int pageSize, double longitude, double latitude, int maxDistance)
        {
   
            IList<IPipelineStageDefinition> stages = new List<IPipelineStageDefinition>();
            string temp1 = "";
            if (!string.IsNullOrEmpty(keywords))
            {
                temp1 = "{\"$geoNear\": {\"near\": {\"type\": \"Point\",\"coordinates\": [" + longitude + "," + latitude + "]},\"distanceField\": \"distance\",\"spherical\": true,\"maxDistance\": " + maxDistance + ",query:{\"address\": { $regex: '" + keywords + "' }}}}";
            }
            else
            {
                temp1 = "{\"$geoNear\": {\"near\": {\"type\": \"Point\",\"coordinates\": [" + longitude + "," + latitude + "]},\"distanceField\": \"distance\",\"spherical\": true,\"maxDistance\": " + maxDistance + "}}";
            }

            PipelineStageDefinition<Models.MongoEnity.mapinfo, Models.MongoEnity.mapinfo> stage1 = new JsonPipelineStageDefinition<Models.MongoEnity.mapinfo, Models.MongoEnity.mapinfo>(temp1);
            stages.Add(stage1);

            string temp2 = "{$skip:" + (pageIndex - 1) * pageSize + "}";
            PipelineStageDefinition<Models.MongoEnity.mapinfo, Models.MongoEnity.mapinfo> stage2 = new JsonPipelineStageDefinition<Models.MongoEnity.mapinfo, Models.MongoEnity.mapinfo>(temp2);
            stages.Add(stage2);

            string temp3 = "{$limit:" + pageSize + "}";
            PipelineStageDefinition<Models.MongoEnity.mapinfo, Models.MongoEnity.mapinfo> stage3 = new JsonPipelineStageDefinition<Models.MongoEnity.mapinfo, Models.MongoEnity.mapinfo>(temp3);
            stages.Add(stage3);

            PipelineDefinition<Models.MongoEnity.mapinfo, Models.MongoEnity.mapinfo> pipeline = new PipelineStagePipelineDefinition<Models.MongoEnity.mapinfo, Models.MongoEnity.mapinfo>(stages);

            //聚合结果
            List<Models.MongoEnity.mapinfo> result = _mapinfoHelper.GetCollection(nameof(Models.MongoEnity.mapinfo)).Aggregate(pipeline).ToList();

            return result;
        }
    }           

Action

[HttpGet]
        public IActionResult TestQueryNear()
        {
            var data = _mapinfoMongoRepository.QueryNear(keywords: string.Empty, pageIndex: 1, pageSize: 2, longitude: 119.627438, latitude: 29.078988, maxDistance: 15000);
            return Ok(data);
        }           

查询结果:

Asp.Net Core MongoDB 空间定位(点)与距离检索

查询结果

查询结果 distance单位是米

[
  {
    "id": "64ae31fe6412e519c80f4b3d",
    "address": "星月花园",
    "name": "星月花园",
    "distance": 797.0567583679608,
    "location": {
      "Coordinates": {
        "Values": [
          119.635592,
          29.078292
        ],
        "Longitude": 119.635592,
        "Latitude": 29.078292
      },
      "Type": 7,
      "BoundingBox": null,
      "CoordinateReferenceSystem": null,
      "ExtraMembers": null
    }
  },
  {
    "id": "64ae31fe6412e519c80f4b3c",
    "address": "西京大厦",
    "name": "西京大厦",
    "distance": 933.0219480837998,
    "location": {
      "Coordinates": {
        "Values": [
          119.63645,
          29.081855
        ],
        "Longitude": 119.63645,
        "Latitude": 29.081855
      },
      "Type": 7,
      "BoundingBox": null,
      "CoordinateReferenceSystem": null,
      "ExtraMembers": null
    }
  }
]           

知识整理不易,喜欢的朋友家个guanzhu呗