Docs HomeMongoDB Manual

Find Restaurants with Geospatial Queries使用地理空间查询查找餐厅

Overview概述

MongoDB's geospatial indexing allows you to efficiently execute spatial queries on a collection that contains geospatial shapes and points. MongoDB的地理空间索引使您能够在包含地理空间形状和点的集合上高效地执行空间查询。To showcase the capabilities of geospatial features and compare different approaches, this tutorial will guide you through the process of writing queries for a simple geospatial application.为了展示地理空间功能并比较不同的方法,本教程将指导您完成为简单的地理空间应用程序编写查询的过程。

This tutorial will briefly introduce the concepts of geospatial indexes, and then demonstrate their use with $geoWithin, $geoIntersects, and $nearSphere.本教程将简要介绍地理空间索引的概念,然后演示它们在$geoWithin$geoIntersects$nearSphere中的使用。

Suppose you are designing a mobile application to help users find restaurants in New York City. 假设您正在设计一个移动应用程序来帮助用户在纽约市找到餐馆。The application must:应用程序必须:

  • Determine the user's current neighborhood using $geoIntersects,使用$geoIntersects确定用户的当前邻域,
  • Show the number of restaurants in that neighborhood using $geoWithin, and使用$geoWithin显示该社区的餐馆数量,以及
  • Find restaurants within a specified distance of the user using $nearSphere.使用$nearSphere查找用户指定距离内的餐厅。

This tutorial will use a 2dsphere index to query for this data on spherical geometry.本教程将使用2dsphere索引来查询有关球形几何体的数据。

For more information on spherical and flat geometries, see Geospatial Models.有关球形和平面几何图形的详细信息,请参阅地理空间模型

Distortion扭曲

Spherical geometry will appear distorted when visualized on a map due to the nature of projecting a three dimensional sphere, such as the earth, onto a flat plane.当在地图上可视化时,由于将三维球体(如地球)投影到平面上的性质,球形几何体会出现扭曲。

For example, take the specification of the spherical square defined by the longitude latitude points (0,0), (80,0), (80,80), and (0,80). 例如,以经纬度点(0,0)(80,0)(80,80)(0,80)定义的球面正方形的规格为例。The following figure depicts the area covered by this region:下图显示了该区域所覆盖的区域:

Diagram of a square projected onto a sphere.

Searching for Restaurants搜索餐厅

Prerequisites先决条件

Download the example datasets from https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/neighborhoods.json and https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/restaurants.json. 从下载示例数据集https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/neighborhoods.jsonhttps://raw.githubusercontent.com/mongodb/docs-assets/geospatial/restaurants.jsonThese contain the collections restaurants and neighborhoods respectively.这些分别包含集合restaurantsneighborhoods

After downloading the datasets, import them into the database:下载数据集后,将它们导入数据库:

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

A geospatial index, and almost always improves performance of $geoWithin and $geoIntersects queries.地理空间索引,几乎总是可以提高$geoWithin$geoIntersects查询的性能。

Because this data is geographical, create a 2dsphere index on each collection using mongosh:由于这些数据是地理数据,请使用mongosh在每个集合上创建一个2dsphere索引:

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

Exploring the Data探索数据

Inspect an entry in the newly-created restaurants collection in mongosh:mongosh新建的restaurants集合中查看一个条目:

db.restaurants.findOne()

This query returns a document like the following:此查询返回如下文档:

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

This restaurant document corresponds to the location shown in the following figure:该餐厅文件对应于下图所示的位置:

Map of a single geospatial point.

Because the tutorial uses a 2dsphere index, the geometry data in the location field must follow the GeoJSON format.由于本教程使用2dsphere索引,因此location字段中的几何数据必须遵循GeoJSON格式

Now inspect an entry in the neighborhoods collection:现在检查neighborhoods集合中的条目:

db.neighborhoods.findOne()

This query will return a document like the following:此查询将返回如下文档:

{
geometry: {
type: "Polygon",
coordinates: [[
[ -73.99, 40.75 ],
...
[ -73.98, 40.76 ],
[ -73.99, 40.75 ]
]]
},
name: "Hell's Kitchen"
}

This geometry corresponds to the region depicted in the following figure:该几何图形对应于下图中所示的区域:

Map of a geospatial polygon.

Find the Current Neighborhood查找当前邻居

Assuming the user’s mobile device can give a reasonably accurate location for the user, it is simple to find the user's current neighborhood with $geoIntersects.假设用户的移动设备可以为用户提供一个相当准确的位置,那么使用$geoIntersects可以很容易地找到用户的当前邻居。

Suppose the user is located at -73.93414657 longitude and 40.82302903 latitude. To find the current neighborhood, you will specify a point using the special $geometry field in GeoJSON format:假设用户位于经度-73.93414657和纬度40.82302903。要查找当前邻域,您将使用GeoJSON格式的特殊$geometry字段指定一个点:

db.neighborhoods.findOne({ geometry: { $geoIntersects: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] } } } })

This query will return the following result:此查询将返回以下结果:

{
"_id" : ObjectId("55cb9c666c522cafdb053a68"),
"geometry" : {
"type" : "Polygon",
"coordinates" : [
[
[
-73.93383000695911,
40.81949109558767
],
...
]
]
},
"name" : "Central Harlem North-Polo Grounds"
}

Find all Restaurants in the Neighborhood查找附近的所有餐厅

You can also query to find all restaurants contained in a given neighborhood. 您还可以查询以查找给定社区中包含的所有餐厅。Run the following in mongosh to find the neighborhood containing the user, and then count the restaurants within that neighborhood: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()

This query will tell you that there are 127 restaurants in the requested neighborhood, visualized in the following figure:此查询将告诉您,在请求的社区中有127家餐厅,如下图所示:

Map of all restaurants in a geospatial polygon.

Find Restaurants within a Distance查找距离内的餐厅

To find restaurants within a specified distance of a point, you can use either $geoWithin with $centerSphere to return results in unsorted order, or $nearSphere with $maxDistance if you need results sorted by distance.要查找某个点指定距离内的餐厅,您可以使用$geoWithin$centerSphere以未排序的顺序返回结果,如果您需要按距离排序的结果,则可以使用$nearSphere$maxDistance

Unsorted with $geoWithin使用$geoWithin取消排序

To find restaurants within a circular region, use $geoWithin with $centerSphere. 要在圆形区域内查找餐厅,请使用$geoWithin$centerSphere$centerSphere is a MongoDB-specific syntax to denote a circular region by specifying the center and the radius in radians.$centerSphere是MongoDB特有的语法,通过以弧度指定中心和半径来表示圆形区域。

$geoWithin does not return the documents in any specific order, so it may show the user the furthest documents first.不按任何特定顺序返回文档,因此它可能会首先向用户显示最远的文档。

The following will find all restaurants within five miles of the user:以下将查找用户五英里范围内的所有餐厅:

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

$centerSphere's second argument accepts the radius in radians, so you must divide it by the radius of the earth in miles. $centerSphere的第二个参数接受以弧度为单位的半径,因此必须将其除以以英里为单位的地球半径。See Convert Distance to Radians for Spherical Operators for more information on converting between distance units.有关在距离单位之间转换的详细信息,请参阅球形运算符的将距离转换为弧度

Sorted with $nearSphere使用$nearSphere排序

You may also use $nearSphere and specify a $maxDistance term in meters. 您也可以使用$nearSphere并以米为单位指定$maxDistance项。This will return all restaurants within five miles of the user in sorted order from nearest to farthest:这将按从最近到最远的排序返回用户五英里内的所有餐厅:

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