MongoDB CRUD操作:地理位置查詢
文章目錄
- MongoDB CRUD操作:地理位置查詢
- 地理空間數據
- GeoJSON對象
- 傳統坐標對
- 通過數組指定(首選)
- 通過嵌入文檔指定
- 地理空間索引
- 2dsphere
- 2d
- 地理空間查詢
- 地理空間查詢運算符
- 地理空間聚合階段
- 地理空間模型
- 舉例
MongoDB支持地理空間數據的查詢,這是MongoDB數據庫有別于其它數據庫的特色之一,在進行GIS相關系統開發的時候會比較有幫助。本文重點介紹MongoDB的地理空間功能。
地理空間數據
在MongoDB中,可以將地理空間數據存儲為GeoJSON對象或傳統坐標對。
GeoJSON對象
要計算類地球體上的幾何形狀,可將位置數據存儲為GeoJSON對象,GeoJSON對象是一個內嵌文檔:
- 名為 type 的字段,指定 GeoJSON對象類型
- 名為坐標的字段,用于指定對象的坐標。
<field>: { type: <GeoJSON type> , coordinates: <coordinates> }
注意:
經緯度坐標的第一個元素是經度第二個元素是緯度。其中經度值介于-180和180之間(含)。有效的緯度值介于-90和90之間(含)。
例如,一個GeoJSON的點:
location: {type: "Point",coordinates: [-73.856077, 40.848447]
}
關于對GeoJSON對象的地理空間查詢在球體上計算,MongoDB 使用WGS84參考系統對GeoJSON對象進行地理空間查詢。
傳統坐標對
要計算歐幾里得平面上的距離,需將位置數據存儲為傳統坐標對并使用2d索引。如果手動將數據轉換為GeoJSON點類型,MongoDB將通過使用2dsphere索引支持傳統坐標對上的球面計算。
要將數據指定為傳統坐標對,可以使用數組(首選)或嵌入式文檔。
通過數組指定(首選)
<field>: [ <x>, <y> ]
指定經緯度坐標時,則指定經度,再指定緯度。
<field>: [<longitude>, <latitude> ]
- 有效的經度值介于 -180 和 180 之間(包含)。
- 有效的緯度值介于 -90 和 90 之間(包含)。
通過嵌入文檔指定
<field>: { <field1>: <x>, <field2>: <y> }
如果指定緯度和經度坐標,則無論字段名稱如何,第一個字段都必須包含經度值,第二個字段必須包含緯度值,即:
<field>: { <field1>: <longitude>, <field2>: <latitude> }
- 有效的經度值介于 -180 和 180 之間(包含)。
- 有效的緯度值介于 -90 和 90 之間(包含)。
指定舊坐標對,數組優于嵌入文檔,因為某些語言不保證關聯映射順序。
地理空間索引
MongoDB 提供以下地理空間索引類型來支持地理空間查詢:
2dsphere
2dsphere 索引支持計算類地球體幾何圖形的查詢。
可使用db.collection.createIndex()創建2dsphere索引,并指定字符串"2dsphere"作為索引類型:
db.collection.createIndex( { <location field> : "2dsphere" } )
其中,<location field>
是一個字段,其值為GeoJSON對象或傳統坐標對。
**注意:**在包含geoJSON點數組的字段上創建索引,將失敗并返回錯誤信息:MongoServerError:索引構建失敗
。
2d
2d索引支持在二維平面幾何圖形的查詢,雖然2d索引可以支持在球面上的$nearSphere
查詢,但還是建議盡量使用2dsphere索引進行球面查詢。
可使用db.collection.createIndex()創建2dsphere索引,并指定字符串"2d"作為索引類型:
db.collection.createIndex( { <location field> : "2d" } )
<location field>
字段的值是一個傳統坐標對。
地理空間查詢
注意:使用二維索引查詢球形數據可能會返回不正確的結果或錯誤。例如,二維索引不支持圍繞極點的球形查詢。
地理空間查詢運算符
MongoDB 提供以下地理空間查詢操作符:
運算符 | 描述 |
---|---|
$geoIntersects | 選擇與GeoJSON幾何圖形相交的幾何圖形。2dsphere索引支持 $geoIntersects |
$geoWithin | 在邊界 GeoJSON 幾何圖形中選擇幾何圖形。2dsphere 和 2d 索引都支持 $geoWithin |
$near | 返回靠近某個點的地理空間對象。需要地理空間索引。 2dsphere 和 2d 索引都支持$near |
$nearSphere | 返回球體上某個點附近的地理空間對象。需要地理空間索引。 2dsphere 和 2d 索引都支持 $nearSphere |
地理空間聚合階段
MongoDB支持$geoNear
地理空間聚合管道階段,可根據與地理空間點的接近程度返回有序的文檔流,合并了地理空間數據的$match
、$sort
和 $limit
的功能,輸出文檔包括附加距離字段,并且可以包括位置標識符字段。$geoNear
要求地理空間索引。
地理空間模型
MongoDB 地理空間查詢可解釋平面或球面上的幾何圖形,2dsphere索引只支持球面查詢(即解釋球面上幾何圖形的查詢),2d索引支持平面查詢(即解釋平面上幾何圖形的查詢)和部分球面查詢,雖然 2d 索引支持某些球面查詢,但在這些球面查詢中使用2d索引可能會導致錯誤。所以,建議盡量使用 2dsphere 索引進行球形查詢。
下表列出了每個地理空間操作使用的地理空間查詢操作符、支持的查詢:
操作 | 球形/平面查詢 | 說明 |
---|---|---|
$near (本行和下一行的GeoJSON質心點,2dsphere索引) | 球形 | 參考$nearSphere 運算符,它在與 GeoJSON 和 2dsphere 索引一起使用時提供相同的功能 |
$near (傳統坐標,2D 索引) | 平面 | |
$nearSphere (GeoJSON 點,2dsphere 索引) | 球形 | 提供與使用 GeoJSON點和2dsphere索引的$near 操作相同的功能。對于球形查詢,最好使用$nearSphere ,在名稱中顯式指定球形查詢,而不是$near 運算符 |
$nearSphere (傳統坐標,2d索引) | 球面 | 使用GeoJSON替代 |
$geoWithin : { $geometry: ... } | 球面 | |
$geoWithin : { $box: ... } | 平面 | |
$geoWithin : { $polygon: ... } | 平面 | |
$geoWithin : { $center: ... } | 平面 | |
$geoWithin : { $centerSphere: ... } | 球面 | |
$geoIntersects | 球面 | |
$geoNear 聚合階段(2dsphere索引) | 球面 | |
$geoNear 聚合階段(2d索引)) | 平面 |
舉例
使用下面的腳本創建places
集合:
db.places.insertMany( [{name: "Central Park",location: { type: "Point", coordinates: [ -73.97, 40.77 ] },category: "Parks"},{name: "Sara D. Roosevelt Park",location: { type: "Point", coordinates: [ -73.9928, 40.7193 ] },category: "Parks"},{name: "Polo Grounds",location: { type: "Point", coordinates: [ -73.9375, 40.8303 ] },category: "Stadiums"}
] )
先在location
字段上創建2dsphere索引:
db.places.createIndex( { location: "2dsphere" } )
下面的查詢使用$near
運算符返回距離指定GeoJSON點至少1000米、最多 5000米的文檔,并按從最近到最遠的順序排序:
db.places.find({location:{ $near:{$geometry: { type: "Point", coordinates: [ -73.9667, 40.78 ] },$minDistance: 1000,$maxDistance: 5000}}}
)
下面的操作使用$geoNear
聚合操作返回與查詢過濾器{category: "Parks" }
匹配的文檔,并按照距指定GeoJSON點從最近到最遠的順序排序:
db.places.aggregate( [{$geoNear: {near: { type: "Point", coordinates: [ -73.9667, 40.78 ] },spherical: true,query: { category: "Parks" },distanceField: "calcDistance"}}
] )