MongoDB的一個特色就是具有豐富的查詢接口,比如地理位置查詢。
在地理位置查詢上,MongoDB有着比傳統關系型數據庫的優勢,下面舉個例子。
當前移動互聯網應用,按用戶離目標門店距離排序上的場景很多。
比如:
一張門店表shop_list,表結構字段包括shop_id,shop_name,lng,lat (門店id,門店名稱,以及門店的經緯度等)。
現收集到當前用戶的所處位置的經緯度是,經度116.30759,緯度40.05748。獲取距離用戶1000m以內的100家門店,按照距離從近到遠排序。
MySql的查詢語句如下:
SELECT shop_id,shop_name,lng,lat, ROUND(6378.138*2*ASIN(SQRT(POW(SIN((40.05748*PI()/180-lat*PI()/180)/2),2)+COS(40.05748*PI()/180)*COS(lat*PI()/180)*POW(SIN((116.30759*PI()/180-lng*PI()/180)/2),2)))*1000) AS distance FROM shop_list HAVING distance < 1000 ORDER BY distance LIMIT 100;
一個這樣的計算方法,顯然mysql性能比較差。
下面的這個計算方法更快一些,效果和上面的幾乎差不多,只是距離distance並不真實。如果只想按照距離排序查出結果是沒問題的。
SELECT shop_id , shop_name , lng , lat , POWER(lat - 40.05748 , 2) + POWER(lng - 116.30759 , 2) * POWER(COS((lat + 40.05748) / 2) , 2) AS distance FROM shop_list HAVING distance < 1000 ORDER BY distance LIMIT 100;
換做MongoDB會如何呢?
首先,要明確MongoDB在使用距離查詢時,存儲的經緯度結構要類似這樣才可以:
'point' : [ 116.299, 40.053 ]
或者: 'point' : { 'lng' : 116.299, 'lat' : 40.053 }
然后給經緯度的point做一個2dSphere索引。具體參考官方文檔:
db.shop_list.createIndex({"point":"2dsphere"})
第三個用法可以得出距離值:
#這個點的附近 db.shop_list.find({'point':{$nearSphere: [116.30759, 40.05748]}}) #這個點的附近1000米 db.shop_list.find({point: { $geoWithin: { $centerSphere: [ [ 116.30759, 40.05748 ], 1000/6378137 ] } } }) #這個點的附近1000米的10個門店,並且有距離計算值 db.runCommand({ geoNear : "shop_list" , near : [ 116.30759, 40.05748], num : 10 , spherical:true, distanceMultiplier: 6378137, maxDistance:1000/6378137})