文档菜单
文档首页
/
MongoDB 手册
/ /

使用地理空间查询查找餐厅

本页内容

  • 概述
  • 扭曲
  • 搜索餐厅

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

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

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

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

  • 使用$geoWithin显示该社区中的餐厅数量

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

本教程将使用2dsphere索引在球形几何上查询这些数据。

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

由于将三维球体(如地球)投影到平面上的性质,球面几何在地图上显示时会失真。

例如,考虑由经纬度点定义的球面正方形规范 (0,0)(80,0)(80,80)(0,80)。以下图显示了该区域覆盖的区域

Diagram of a square projected onto a sphere.
点击放大

从以下位置下载示例数据集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:

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"
}

此餐厅文档对应以下图示的位置

Map of a single geospatial point.

因为教程使用了 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"
}

此几何形状对应以下图示的区域

Map of a geospatial polygon.
点击放大

假设用户的移动设备可以提供用户位置的合理准确度,使用 $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家餐厅,如图所示

Map of all restaurants in a geospatial polygon.
点击放大

要查找距离某点特定距离内的餐厅,您可以使用带有 $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 } } })

返回

地理空间查询