iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 20
0
AI & Data

從入門到精通 MongoDB系列 第 24

Day24: MongoDB 中的地理空間資料處理

在這篇文章中我們將會介紹如何在 MongoDB 中處理地理空間資料,透過 GeoJSON 的資料格式來執行地理空間資料的操作。


GeoJSON 物件

我們在使用 Google Map 查詢位置資訊時,可以在 URL 中的 "@" 後發現有一組座標資訊的數值,如下圖中我們使用 Google Map 查詢「台北101」的網址中,在 @ 後的數值組 "25.033976,121.5623502" 依序分別為 緯度 latitude經度 longitude

而 MongoDB 支持 GeoJSON 這個專門用來儲存地理位置資訊的資料格式。

GeoJSON Objects

GeoJSON 是一種專門處理地理資訊(GIS)結構的 JSON 標準格式。 一個 GeoJSON 物件可以用來代表點(Point)、線(LineString)、多邊形(Polygon)等幾何結構,以及特徵(Feature)的集合,或是一系列的特徵(FeatureCollection)。

GeoJSON 物件必須使用嵌入式文件(embedded document)的形式,而 field 欄位有 type 及 coordinate:

  • type
    • Point:點
    • LineString:直線
    • Polygon:多邊形
    • MultiPoint
    • MultiLineString
    • MultiPolygon
    • GeometryCollection
  • coordinates:由經度及緯度組成的 list

關於 GeoJSON,詳細可以參考官方文件

實作 Point 類別的 GeoJSON

接著來實作 point 類別的 GeoJSON,我們新增一個「台北 101」位置資訊的 GeoJSON:db.taiwan.insertOne({name: "Taipei 101", position: {type: "Point", coordinates: [121.5623502, 25.033976]}})

使用 find() 來查看剛建立的 GeoJSON object:db.taiwan.find().pretty()

可以看到在 position 中的兩個 field 分別儲存了 type 類別及 coordinates 座標的資訊。


尋找附近的餐廳

先使用 findOne() 來檢視 restaurant.json 這個有 25359 個 documents 的 collection 的資料結構:db.restaurant.findOne()

接著使用第一筆餐廳的經緯度到 Google Map 查詢:(40.579505, -73.98241999999999)

找尋附近的餐廳

假設目前的位置是第一個餐廳的位置:(40.5795091, -73.984614)

我們先建位置的索引:db.restaurant.createIndex({location: "2dsphere"})

來查看剛建的索引:db.restaurant.getIndexes()

此時,可以透過以下指令來查詢方圓 300 公尺內的餐廳:db.restaurant.find({ location: { $nearSphere: { $geometry: { type: "Point", coordinates: [-73.984614, 40.5795091] }, $maxDistance: 300 } } })

來講解一下指令中的其中三個部分:

  • $nearSphere:查詢距離幾公尺內的點
  • $geometry:查詢的基準點
  • $maxDistance:查詢的範圍為幾公尺

如果我們將最大範圍改成 100 公尺:maxDistance: 100

如果我們想要針對查詢結果進行排序,距離由小到大做排序,可以使用 聚合 的方式來達成:db.restaurant.aggregate([{ $geoNear: {near: { type: "Point", coordinates: [-73.984614, 40.5795091] }, distanceField: "dist.calculated", maxDistance: 100, includeLocs: "dist.location", spherical: true }}]).pretty()

可以從結果得知,最近的餐廳距離 52 公尺,第二近的餐廳距離 86 公尺。


判斷是否在某一區域內

我們將在這小節介紹如何判斷是否在同一個區域內。

先使用 findOne() 來查看 neighborhood.json 這個地理資料:db.neighborhood.findOne()

可以看出來 neighborhood.json 中的每筆資料都是由多個點組成的多邊形區域範圍。而共有 9 個區域範圍:db.neighborhood.find().count()

判斷位置是否在某一個區域內

假設要判斷的位置是 (40.60855546746685, -73.94187230011019)。

使用以下指令來查詢這個位置是否在 neighborhood 中的任一個區域範圍中:db.neighborhood.findOne({ geometry: { $geoIntersects: { $geometry: { type: "Point", coordinates: [-73.94187230011019, 40.60855546746685]}}}})

從查詢結果可以發現 (40.60855546746685, -73.94187230011019) 這個位置位於 "Madison" 這個區域內。


今天介紹了如何在 MongoDB 中進行對 GeoJSON 資料的操作,下一篇開始會進入 MongoDB 中最重要的觀念 - 聚合 Aggregation


上一篇
Day23: 索引 index(4) - 聯合索引 Compound Indexes 與文本索引 Text Index
下一篇
Day25: 聚合(Aggregation)操作(1) - Aggregation pipeline
系列文
從入門到精通 MongoDB26

尚未有邦友留言

立即登入留言