地理空间查询
MongoDB 支持对地理空间数据进行查询操作。本节介绍了 MongoDB 的地理空间功能。
兼容性
您可以对以下环境中托管的部署使用地理空间查询:
MongoDB Atlas:用于云中 MongoDB 部署的完全托管服务
MongoDB Enterprise:基于订阅、自我管理的 MongoDB 版本
MongoDB Community:源代码可用、免费使用且可自行管理的 MongoDB 版本
Filter对于 MongoDB Atlas 中托管的部署,您可以在用户界面中使用查询筛选器栏或聚合构建器来运行地理空间查询。要了解更多信息,请参阅在 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 对象。
对 GeoJSON 对象的 MongoDB 地理空间查询在球体上进行计算;MongoDB 使用 WGS84 参考系统对 GeoJSON 对象进行地理空间查询。
传统坐标对
要计算欧几里得平面上的距离,请将位置数据存储为旧版坐标对,并使用 2d
索引。手动将数据转换为 GeoJSON 点类型后,MongoDB 支持通过 2dsphere
索引对旧版坐标对进行球面计算
要将数据指定为传统坐标对,可以使用数组(首选)或嵌入式文档。
- 通过数组指定(首选):
<field>: [ <x>, <y> ] 如果指定纬度和经度坐标,则先列出 longitude,然后列出 latitude;即
<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" } )
其中 <location field>
是一个字段,其值为 GeoJSON 对象或旧版坐标对。
注意
如果尝试在包含 geoJSON 点数组的字段上创建索引,索引构建将失败并返回以下错误:
MongoServerError: Index build failed
有关 2dsphere
索引的更多信息,请参阅 2dsphere 索引。
2d
2d 索引支持在二维平面上计算几何图形的查询。虽然该索引支持在球面上计算的 $nearSphere
查询,但尽可能使用 2dsphere
索引进行球面查询。
要创建 2d
索引,请使用 db.collection.createIndex()
方法,将位置字段指定为键,并将字符串字面量 "2d"
指定为索引类型:
db.collection.createIndex( { <location field> : "2d" } )
其中 <location field>
是一个字段,其值是旧版坐标对。
有关 2d
索引的更多信息,请参阅 2d 索引。
地理空间查询
注意
使用 2d
索引查询球形数据可能会返回不正确的结果或错误。例如,2d
索引不支持环绕极点的球形查询。
地理空间查询操作符
MongoDB 提供以下地理空间查询操作符:更多详情(包括示例),请参阅各个参考页。
名称 | 说明 |
---|---|
注意
时间序列集合仅支持 $geoNear
聚合阶段,用于对来自2 dsphere 索引查询的地理空间数据进行排序。不能在时间序列集合中使用 $near
和 $nearSphere
操作符
地理空间聚合阶段
MongoDB 提供以下地理空间聚合管道阶段:
阶段 | 说明 |
---|---|
更多详情(包括示例),请参阅 $geoNear
参考页。
地理空间模型
MongoDB 地理空间查询可以解释平面或球面上的几何图形。
2dsphere
索引仅支持球面查询(即解释球面上几何图形的查询)。
2d
索引支持平面查询(即,解释平面上几何图形的查询)和某些球面查询。虽然 2d
索引支持某些球面查询,但对此类球面查询使用 2d
索引可能会导致错误。如果可能,请使用 2dsphere
索引进行球面查询。
下表列出了每个地理空间操作使用的地理空间查询运算符和支持的查询:
操作 | 球形/平面查询 | 注意 |
---|---|---|
球形 | ||
平面 | ||
球形 | 提供与 对于球面查询,最好使用在名称中显式指定球面查询的 | |
球形 | 使用 GeoJSON 点。 | |
$geoWithin : { $geometry : ... } | 球形 | |
$geoWithin : { $box : ... } | 平面 | |
$geoWithin : { $polygon : ... } | 平面 | |
$geoWithin : { $center : ... } | 平面 | |
$geoWithin : { $centerSphere : ... } | 球形 | |
球形 | ||
球形 | ||
平面 |
在 Atlas 中执行地理空间查询
您可以使用 MongoDB Atlas 用户界面在 Atlas 中执行地理空间查询。
创建索引
如果您的地理空间集合还没有地理空间索引,则必须创建一个。
为该集合选择数据库。
主面板和左侧的 Namespaces 列出数据库中的集合。
选择集合。
在左侧或主面板中选择包含地理空间数据的集合。主面板显示 Find、Indexes 和 Aggregation 视图。
选择“索引”视图。
打开 Index 视图后,Atlas 会显示集合中存在的所有索引。
定义地理类型的索引
按 Create Index 按钮。
定义地理类型索引。请参阅如何为 GeoJSON 对象构建索引。
查询地理空间数据
选择“查找”视图。
从包含地理空间数据的集合中,选择 Find 标签页以查看地理空间集合。
输入查询。
在Filter文本框中输入查询。使用任意地理空间查询操作符对地理空间数据执行相关查询。地理空间查询可能类似于以下内容:
{ "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 ] ] ] } } } } 按“应用”按钮。
按 Apply 按钮应用您的查询。Atlas 会过滤地理空间数据,以仅显示与您的地理空间查询相匹配的文档。
您可以在 MongoDB Atlas UI 中创建和执行聚合管道,以进行地理空间查询。
创建您的地理空间查询聚合管道
选择聚合阶段。
从左下角面板的 Select(选择)下拉菜单中选择聚合阶段。
下拉列表右侧的切换指示是否已启用该阶段。
使用
$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 点 1,000-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" } } ] )