目录
进入MongoDB中文手册(4.2版本)目录
1 概述
MongoDB的地理空间索引使您可以高效地对包含地理空间形状和点的集合执行空间查询。为了展示地理空间特性的能力并比较不同的方法,本教程将指导您完成一个简单的地理空间查询的应用程序的编写。
本教程将简要介绍地理空间索引的概念,然后通过$geoWithin, $geoIntersects和$nearSphere展示它们的使用。
假设您正在设计一个移动应用程序,以帮助用户找到纽约市的餐馆。该应用程序必须:
- 通过$geoIntersects确定用户当前的附近地区,
- 使用$geoWithin显示附近的餐厅数量,
- 并且使用$nearSphere查找在用户指定距离内的餐厅 。
本教程将使用2dsphere索引来查询有关球形几何的数据。
有关球面和平面几何的更多信息,请参见地理空间模型(Geospatial Models)。
2 失真
当将三维球体(例如地球)投影到平面上,并在地图上显示时,球形几何形状将失真。
例如,下图描绘了被经度纬度点(0,0),(80,0),(80,80),和 (0,80)确定的球面正方形(spherical square)覆盖的区域:
3 搜索餐厅
3.1 前提条件
从
和 https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/restaurants.json下载示例数据集 。他们分别包含restaurants和neighborhoods集合。
下载数据集后,将它们导入数据库:
mongoimport <restaurants.json的路径> -c=restaurants
mongoimport <neighborhoods.json的路径> -c=neighborhoods
地理空间索引,几乎总是可以提高
g
e
o
W
i
t
h
i
n
和
geoWithin和
geoWithin和geoIntersects 查询的性能。
由于此数据是地理数据,因此请使用mongoShell在每个集合上创建2dsphere索引:
db.restaurants.createIndex({ location: "2dsphere" })
db.neighborhoods.createIndex({ geometry: "2dsphere" })
3.2 查找数据
在mongo shell中检查新创建的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"
}
该几何形状对应于下图所示的区域:
3.3 找到当前Neighborhood
假设用户的移动设备可以为用户提供合理准确的位置,则使用 g e o I n t e r s e c t s 即 可 轻 松 找 到 用 户 的 当 前 n e i g h b o r h o o d 。 假 设 用 户 位 于 经 度 − 73.93414657 和 纬 度 40.82302903 。 要 找 到 当 前 n e i g h b o r h o o d , 您 将 使 用 G e o J S O N 格 式 的 geoIntersects即可轻松找到用户的当前neighborhood 。 假设用户位于经度-73.93414657和纬度40.82302903。要找到当前neighborhood ,您将使用GeoJSON格式的 geoIntersects即可轻松找到用户的当前neighborhood。假设用户位于经度−73.93414657和纬度40.82302903。要找到当前neighborhood,您将使用GeoJSON格式的geometry字段指定一个点 :
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"
}
3.4 找到Neighborhood中的所有餐馆
您还可以查询到给定neighborhood中包含的所有餐馆。在mongo shell中运行以下命令,找到包含用户的neighborhood,然后对neighborhood中的餐馆计数:
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家餐厅,如下图所示:
3.5 找到一定距离范围内的餐馆
要找到一个点的指定距离内的餐馆,您可以使用$geoWithin与$centerSphere返回在未排序结果,或如果您需要的结果要按距离排序则使用$nearSphere与$maxDistance。
3.6 使用$geoWithin不排序
使用$geoWithin与$centerSphere可以一个圆形区域内找到餐馆。$centerSphere是MongoDB特定的语法,用于指定弧度的中心和半径来表示圆形区域。
$geoWithin不会以任何特定顺序返回文档,因此它可能首先向用户显示最远的文档。
以下内容将查找距用户五英里范围内的所有餐馆:
db.restaurants.find({ location:
{ $geoWithin:
{ $centerSphere: [ [ -73.93414657, 40.82302903 ], 5 / 3963.2 ] } } })
$centerSphere的第二个参数接受弧度的半径,因此必须将其除以以英里为单位的地球半径。有关在距离单位之间进行转换的更多信息,请参见使用球面几何计算距离。
3.7 使用$nearSphere排序
您也可以使用$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 } } })