Docs 菜单

Docs 主页开发应用程序MongoDB Manual

通过地理空间查询查找餐厅

在此页面上

  • 概述
  • 失真
  • 搜索餐厅

通过 MongoDB 的地理空间索引,可以在包含地理空间形状和点的集合上高效地执行空间查询。为了展示地理空间特征的功能并比较不同的方法,本教程将指导您完成为简单的地理空间应用程序编写查询语句的过程。

本教程将简要介绍地理空间索引的概念,然后演示其与 $geoWithin$geoIntersects$nearSphere 的用法。

假设您正在设计一个移动应用程序来帮助用户查找纽约市的餐厅。该应用程序必须:

  • 使用 $geoIntersects 确定用户的当前社区,

  • 使用 $geoWithin 显示该社区中的餐馆数量,以及

  • 使用 $nearSphere 查找用户指定距离内的餐厅。

本教程将使用 2dsphere 索引来查询有关球面几何的数据。

有关球面和平面几何图形的更多信息,请参阅地理空间模型。

由于将三维球体(例如地球)投影到平面的特质,球面几何图形在地图上进行可视化时会出现变形。

以由经纬度点 (0,0)(80,0)(80,80)(0,80) 所定义的球面正方形的规范为例。下图描绘了该地区所涵盖的范围:

投影到球体上的正方形示意图。
点击放大

https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/neighborhoods.json 下载示例数据集 和 https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/restaurants.json 。它们分别包含集合restaurantsneighborhoods

下载数据集后,将其导入数据库:

mongoimport <path to restaurants.json> -c=restaurants
mongoimport <path to neighborhoods.json> -c=neighborhoods

地理空间索引,几乎总能提高 $geoWithin$geoIntersects 查询的性能。

由于此数据是地理数据,因此使用mongosh在每个集合上创建一个2dsphere索引:

db.restaurants.createIndex({ location: "2dsphere" })
db.neighborhoods.createIndex({ geometry: "2dsphere" })

检查mongosh中新创建的restaurants集合中的条目:

db.restaurants.findOne()

此查询将返回如下所示文档:

{
location: {
type: "Point",
coordinates: [-73.856077, 40.848447]
},
name: "Morris Park Bake Shop"
}

该餐厅文档对应下图中所示的位置:

单个地理空间点的地图。

由于本教程使用 2dsphere 索引,因此 location 字段中的几何数据必须遵循 GeoJSON 格式

现在,检查 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"
}

您还可以查询以查找给定社区中包含的所有餐厅。在mongosh中运行以下命令以查找包含该用户的社区,然后计算该社区内的餐厅数量:

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$centerSphere$centerSphere 是一种特定于 MongoDB 的语法,通过以弧度为单位指定中心和半径来表示圆形区域。

$geoWithin 不会以任意特定顺序返回文档,因此它可能会先向用户展示距离中心最远的文档。

以下示例将查找距离用户五英里范围内的所有餐厅:

db.restaurants.find({ location:
{ $geoWithin:
{ $centerSphere: [ [ -73.93414657, 40.82302903 ], 5 / 3963.2 ] } } })

$centerSphere的第二个参数接受弧度制的半径,因此您必须将其除以地球的半径(以英里为单位)。 有关距离单位之间转换的更多信息,请参阅使用球面几何计算距离

此外,也可使用 $nearSphere 并以米为单位来指定 $maxDistance 项。此操作会按从最近到最远的排序顺序返回距离用户五英里范围内的所有餐厅:

var METERS_PER_MILE = 1609.34
db.restaurants.find({ location: { $nearSphere: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] }, $maxDistance: 5 * METERS_PER_MILE } } })
← 地理空间查询