查找具有地理空间查询的餐厅
在本页面
Overview
MongoDB 的geospatial索引使您可以有效地对包含地理空间形状和点的集合执行空间查询。本教程将简要介绍地理空间索引的概念,然后通过$geoWithin,$geoIntersects和geoNear演示它们的用法。
为了展示地理空间要素的功能并比较不同的方法,本教程将指导您完成为简单地理空间应用程序编写查询的过程。
假设您正在设计一个移动应用程序,以帮助用户找到纽约市的餐馆。该应用程序必须:
-
使用$geoIntersects确定用户的当前邻居,
-
使用$geoWithin显示该社区中的餐馆数量
-
使用$nearSphere在用户指定距离内查找餐馆。
本教程将使用2dsphere
索引来查询有关球形几何的数据。
有关球面和平面几何的更多信息,请参见Geospatial Models。
Distortion
由于将三维球体(例如地球)投影到平面上的性质,当在 Map 上可视化时,球形几何形状将显得失真。
例如,以经度纬度点(0,0)
,(80,0)
,(80,80)
和(0,80)
定义的球面正方形的规格为例。下图描述了此区域覆盖的区域:
搜索餐厅
Prerequisites
从https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/neighborhoods.json和https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/restaurants.json下载示例数据集。它们分别包含集合restaurants
和neighborhoods
。
下载数据集后,将它们导入数据库:
mongoimport <path to restaurants.json> -c restaurants
mongoimport <path to neighborhoods.json> -c neighborhoods
geoNear命令需要地理空间索引,并且几乎总是可以提高$geoWithin和$geoIntersects查询的性能。
由于此数据是地理数据,因此请使用mongo shell 在每个集合上创建2dsphere
索引:
db.restaurants.createIndex({ location: "2dsphere" })
db.neighborhoods.createIndex({ geometry: "2dsphere" })
探索数据
从mongo shell 中检查新创建的restaurants
集合中的条目:
db.restaurants.findOne()
该查询返回如下文档:
{
location: {
type: "Point",
coordinates: [-73.856077, 40.848447]
},
name: "Morris Park Bake Shop"
}
该餐厅文档对应于下图所示的位置:
由于本教程使用2dsphere
索引,因此location
字段中的几何数据必须遵循GeoJSON format。
现在检查neighborhoods
集合中的条目:
db.neighborhoods.findOne()
该查询将返回如下文档:
{
geometry: {
type: "Polygon",
coordinates: [[
[ -73.99, 40.75 ],
...
[ -73.98, 40.76 ],
[ -73.99, 40.75 ]
]]
},
name: "Hell's Kitchen"
}
该几何形状对应于下图所示的区域:
查找当前邻居
假设用户的移动设备可以为用户提供合理准确的位置,则很容易使用$geoIntersects查找用户的当前邻居。
假设用户位于-73.93414657 经度和 40.82302903 纬度。要找到当前邻域,您将使用特殊的$geometry字段以GeoJSON格式指定一个点:
db.neighborhoods.findOne({ geometry: { $geoIntersects: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] } } } })
该查询将返回以下结果:
{
"_id" : ObjectId("55cb9c666c522cafdb053a68"),
"geometry" : {
"type" : "Polygon",
"coordinates" : [
[
[
-73.93383000695911,
40.81949109558767
],
...
]
]
},
"name" : "Central Harlem North-Polo Grounds"
}
查找附近的所有餐厅
您还可以查询以查找给定社区中包含的所有餐馆。在mongo shell 中运行以下命令以找到包含用户的社区,然后计算该社区中的餐馆:
var neighborhood = db.neighborhoods.findOne( { geometry: { $geoIntersects: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] } } } } )
db.restaurants.find( { location: { $geoWithin: { $geometry: neighborhood.geometry } } } ).count()
该查询将告诉您,所请求的社区中有 127 家餐厅,如下图所示:
寻找远处的餐厅
要查找指定点距离内的餐厅,可以使用$geoWithin和$centerSphere返回未排序的结果,也可以使用nearSphere
和$maxDistance返回需要按距离排序的结果。
未与$ geoWithin 排序
要在圆形区域内查找餐厅,请使用$geoWithin和$centerSphere。 $centerSphere是 MongoDB 特定的语法,通过指定以弧度表示的中心和半径来表示圆形区域。
$geoWithin不会以任何特定 Sequences 返回文档,因此它可能会首先向用户显示最远的文档。
以下内容将查找距用户五英里范围内的所有餐馆:
db.restaurants.find({ location:
{ $geoWithin:
{ $centerSphere: [ [ -73.93414657, 40.82302903 ], 5 / 3963.2 ] } } })
$centerSphere的第二个参数接受以弧度为单位的半径,因此必须将其除以以英里为单位的地球半径。有关在距离单位之间进行转换的更多信息,请参见使用球面几何计算距离。
用$ nearSphere 排序
您也可以使用$nearSphere并以米为单位指定$maxDistance项。这将按照从最近到最远的排序 Sequences 返回距离用户五英里以内的所有餐厅:
var METERS_PER_MILE = 1609.34
db.restaurants.find({ location: { $nearSphere: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] }, $maxDistance: 5 * METERS_PER_MILE } } })