天天看點

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呗