地理空间查询
MongoDB 支持对地理空间数据进行查询操作。本节介绍了 MongoDB 的地理空间功能。
兼容性
您可以使用地理空间查询在以下环境中部署
MongoDB Atlas: 云中 MongoDB 部署的完全托管服务
MongoDB Enterprise: 基于订阅的自托管 MongoDB 版本
MongoDB Community: 可源代码、免费使用和自托管 MongoDB 版本
对于在 MongoDB Atlas 中托管的部署,您可以通过使用查询筛选栏或聚合构建器在 UI 中运行地理空间查询。有关更多信息,请参阅 在 Atlas 中执行地理空间查询。
地理空间数据
在MongoDB中,您可以将地理空间数据存储为GeoJSON对象或作为旧版坐标对。
GeoJSON对象
要计算类似于地球的球体上的几何形状,将您的位置数据存储为GeoJSON对象。
要指定GeoJSON数据,使用具有以下字段的嵌套文档:
名为
type
的字段,用于指定GeoJSON对象类型,以及名为
coordinates
的字段,用于指定对象的坐标。
<field>: { type: <GeoJSON type> , coordinates: <coordinates> }
重要
如果您指定经纬度坐标,请先列出 经度,然后是 纬度。
有效的经度值介于
-180
和180
之间,两者都包含。有效的纬度值介于
-90
和90
之间,两者都包含。
例如,要指定一个GeoJSON点:
location: { type: "Point", coordinates: [-73.856077, 40.848447] }
有关MongoDB支持的GeoJSON对象列表以及示例,请参阅GeoJSON对象。
MongoDB在GeoJSON对象上的地理空间查询是在球体上计算的;MongoDB使用WGS84参考系统在GeoJSON对象上执行地理空间查询。
旧坐标对
为了在欧几里得平面上计算距离,将您的位置数据存储为旧坐标对,并使用一个 2d
索引。如果您手动将数据转换为 GeoJSON 点类型,MongoDB 支持使用 2dsphere
索引在旧坐标对上进行球形表面计算。
要将数据指定为旧坐标对,您可以使用数组(推荐)或内嵌文档。
- 通过数组指定(推荐)
<field>: [ <x>, <y> ] 如果指定经纬度坐标,请先列出 经度,然后是 纬度;即
<field>: [<longitude>, <latitude> ] 有效的经度值介于
-180
和180
之间,两者都包含。有效的纬度值介于
-90
和90
之间,两者都包含。
- 通过内嵌文档指定
<field>: { <field1>: <x>, <field2>: <y> } 如果指定经纬度坐标,无论字段名称如何,第一个字段必须包含 经度 值,第二个字段包含 纬度 值;即
<field>: { <field1>: <longitude>, <field2>: <latitude> } 有效的经度值介于
-180
和180
之间,两者都包含。有效的纬度值介于
-90
和90
之间,两者都包含。
为了指定旧坐标对,数组比内嵌文档更受欢迎,因为某些语言不能保证关联映射的顺序。
地理空间索引
MongoDB 提供以下地理空间索引类型以支持地理空间查询。有关地理空间索引的更多信息,请参阅 地理空间索引。
2dsphere
2dsphere 索引支持计算类似于地球的球体上几何形状的查询。
要创建一个 2dsphere
索引,使用 db.collection.createIndex()
方法,并将字符串字面量 "2dsphere"
作为索引类型指定
db.collection.createIndex( { <location field> : "2dsphere" } )
其中 <位置字段>
是一个值可以是 GeoJSON 对象 或 旧版坐标对 的字段。
注意
如果您尝试在包含 GeoJSON 点数组的字段上创建索引,索引构建将失败并返回以下错误
MongoServerError: 索引构建失败
有关 2dsphere
索引的更多信息,请参阅 2dsphere 索引。
2d
2d 索引支持计算在二维平面上几何形状的查询。尽管索引可以支持在球体上计算的 $nearSphere
查询,但如果可能,请使用 2dsphere
索引进行球体查询。
要创建一个 2d
索引,使用 db.collection.createIndex()
方法,将位置字段指定为键,并将字符串字面量 "2d"
作为索引类型
db.collection.createIndex( { <location field> : "2d" } )
其中 <位置字段>
是一个值是 旧版坐标对 的字段。
有关 2d
索引的更多信息,请参阅 2d 索引。
空间查询
注意
对于球形数据的查询,使用2d索引可能会返回错误结果或错误。例如,2d索引不支持围绕极地环绕的球形查询。
空间查询运算符
MongoDB提供了以下空间查询运算符。有关更多详细信息(包括示例),请参阅相应的参考页面。
名称 | 描述 |
---|---|
选择与GeoJSON几何体相交的几何体。2dsphere索引支持$geoIntersects。 | |
选择在边界GeoJSON几何体内的几何体。2dsphere和2d索引支持$geoWithin。 | |
返回与点邻近的空间对象。需要一个空间索引。2dsphere和2d索引支持$near。 | |
返回与球面上点邻近的空间对象。需要一个空间索引。2dsphere和2d索引支持$nearSphere。 |
注意
时间序列集合仅支持使用 $geoNear
聚合阶段对来自 地理空间数据 的查询进行排序,该阶段针对 2dsphere 索引。您不能在时间序列集合上使用 $near
和 $nearSphere
操作符。
地理空间聚合阶段
MongoDB 提供以下地理空间 聚合管道阶段:
阶段 | 描述 |
---|---|
有关更多详细信息(包括示例),请参阅 $geoNear
参考页面。
地理空间模型
MongoDB 地理空间查询可以解释平面或球面上的几何形状。
2dsphere
索引仅支持球形查询(即解释球面上几何形状的查询)。
2d
索引支持平面查询(即解释平面上的几何形状的查询)和一些球形查询。虽然 2d
索引支持一些球形查询,但使用 2d
索引进行这些球形查询可能会导致错误。如果可能的话,使用 2dsphere
索引进行球形查询。
以下表格列出了地理空间查询运算符,以及每个地理空间操作支持的查询。
操作 | 球形/平面查询 | 备注 |
---|---|---|
球形 | ||
平面 | ||
球形 | 提供与使用 GeoJSON 点和 2dsphere 索引的 对于球形查询,可能更倾向于使用 | |
球形 | 请使用 GeoJSON 点。 | |
$geoWithin : { $geometry : ... } | 球形 | |
$geoWithin : { $box : ... } | 平面 | |
$geoWithin : { $polygon : ... } | 平面 | |
$geoWithin : { $center : ... } | 平面 | |
$geoWithin : { $centerSphere : ... } | 球形 | |
球形 | ||
球形 | ||
平面 |
在 Atlas 中执行地理空间查询
您可以使用 MongoDB Atlas UI 在 Atlas 中执行地理空间查询。
创建索引
如果您的地理空间集合尚未创建地理空间索引,您必须创建一个。
选择集合的数据库。
主面板和左侧的 命名空间 列出数据库中的集合。
选择集合。
在左侧面板或主面板中选择包含您的地理空间数据的集合。主面板显示 查找、索引 和 聚合 视图。
选择索引视图。
当您打开 索引 视图时,Atlas 会显示集合上存在的任何索引。
定义 geo 类型的索引
点击 创建索引 按钮。
定义地理类型索引。请参阅如何索引 GeoJSON 对象。
查询地理空间数据
选择查找视图。
从包含您的地理空间数据的集合中,选择查找选项卡以查看您的地理空间集合。
输入查询。
在筛选器文本框中输入查询。使用任何地理空间查询运算符对您的地理空间数据执行相关查询。一个地理空间查询可能如下所示
{ "coordinates": { $geoWithin: { $geometry: { type: "Polygon", coordinates: [ [ [-80.0, 10.00], [ -80.0, 9.00], [ -79.0, 9.0], [ -79.0, 10.00 ], [ -80.0, 10.0 ] ] ] } } } } 按下应用按钮。
按下应用按钮以应用您的查询。Atlas 将过滤地理空间数据,只显示与您的地理空间查询匹配的文档。
您可以在 MongoDB Atlas UI 中创建和执行聚合管道来执行地理空间查询。
创建您的地理空间查询聚合管道
选择聚合阶段。
在左下角面板中的 选择 下拉列表中选择聚合阶段。
下拉列表右侧的切换按钮决定了该阶段是否启用。
使用
$geoNear
阶段在聚合管道中执行地理空间查询。填写您的聚合阶段。
使用适当的值填写您的阶段。如果 注释模式 已启用,管道构建器为您选定的阶段提供语法指南。
您修改阶段时,Atlas 会根据当前阶段的结果更新右侧的预览文档。
您的
$geoNear
阶段可能如下所示{ near: { type: "Point", coordinates: [ -73.9667, 40.78 ] }, spherical: true, query: { category: "Parks" }, distanceField: "calcDistance" } 根据需要运行其他管道阶段。
示例
创建包含以下文档的集合 places
db.places.insertMany( [ { name: "Central Park", location: { type: "Point", coordinates: [ -73.97, 40.77 ] }, category: "Parks" }, { name: "Sara D. Roosevelt Park", location: { type: "Point", coordinates: [ -73.9928, 40.7193 ] }, category: "Parks" }, { name: "Polo Grounds", location: { type: "Point", coordinates: [ -73.9375, 40.8303 ] }, category: "Stadiums" } ] )
以下操作在 location
字段上创建 2dsphere
索引
db.places.createIndex( { location: "2dsphere" } )
上面的 places
集合具有 2dsphere
索引。以下查询使用 $near
操作符返回距离指定的 GeoJSON 点至少 1000 米且最多 5000 米的文档,按从近到远的顺序排序
db.places.find( { location: { $near: { $geometry: { type: "Point", coordinates: [ -73.9667, 40.78 ] }, $minDistance: 1000, $maxDistance: 5000 } } } )
以下操作使用$geoNear
聚合操作来返回匹配查询过滤器{ category: "Parks" }
的文档,并按距离指定GeoJSON点的最近到最远排序
db.places.aggregate( [ { $geoNear: { near: { type: "Point", coordinates: [ -73.9667, 40.78 ] }, spherical: true, query: { category: "Parks" }, distanceField: "calcDistance" } } ] )