查找具有地理空间查询的餐厅

在本页面

Overview

MongoDB 的geospatial索引使您可以有效地对包含地理空间形状和点的集合执行空间查询。本教程将简要介绍地理空间索引的概念,然后通过$geoWithin$geoIntersectsgeoNear演示它们的用法。

为了展示地理空间要素的功能并比较不同的方法,本教程将指导您完成为简单地理空间应用程序编写查询的过程。

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

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

有关球面和平面几何的更多信息,请参见Geospatial Models

Distortion

由于将三维球体(例如地球)投影到平面上的性质,当在 Map 上可视化时,球形几何形状将显得失真。

例如,以经度纬度点(0,0)(80,0)(80,80)(0,80)定义的球面正方形的规格为例。下图描述了此区域覆盖的区域:

正方形图投影到一个球体上。

搜索餐厅

Prerequisites

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

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

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

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

单个地理空间点的 Map。

由于本教程使用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"
}

该几何形状对应于下图所示的区域:

地理空间多边形的 Map。

查找当前邻居

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

地理空间多边形中所有餐厅的 Map。

寻找远处的餐厅

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