学习mongodb,体会mongodb的每一个使用细节,欢迎阅读威赞的文章。这是威赞发布的第78篇mongodb技术文章,欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题,欢迎在文章下面点个赞,或者关注威赞。谢谢。
通过阅读文档,了解Mongodb除了支持文档查询外,还支持地理信息坐标及临近查询。本文就对Mongodb对地理信息查询的支持进行介绍。
地理信息数据
在Mongodb数据库中,用户可以使用GeoJSON对象或者经纬坐标对的形式来保存地理信息数据。
GeoJSON对象
Mongodb使用GeoJSON对象保存数据以便于在地理空间中进行计算。用户使用嵌入文档的形式定义GeoJSON对象的数据,包括
-
一个名为type的字段,定义了GeoJSON对象的类型
-
一个名为coordinates的字段,指定了对象的坐标信息
<field>: { type: <GeoJSON type>, coordinates: <coordinates>}
如定义一个GeoJSON类型的点
location: {
type: "Point",
coordinates: [-73.856077, 40.848447]
}
当然,Mongodb也支持定义GeoJSON列表,具体可以参考本系列的其他文章。
Mongodb计算地理信息数据时,使用WGS84坐标系。
经纬坐标对
为了计算欧式距离,除了定义GeoJSON对象外,用户还可以将数据保存为经纬坐标对的形式,并建立一个平面二维索引。当用户将经纬坐标对转换成GeoJSON点类型的数据后,利用空间二维索引,Mongodb可以支持曲面空间数据计算。
用户可以使用数组或嵌入文档的形式,来保存坐标对数据。mongodb推荐用户使用数组的形式来保存数据。
<field>: [<x>, <y>]
或者使用经纬度坐标
<field>:[<经度坐标>, <纬度坐标>]
其中经度坐标范围在-180到180之间,包含-180和180. 而纬度坐标是-90到90之间,同样包含-90和90.
使用嵌入式文档的形式来定义坐标对
<field>: {<field1>: <x>, <field2>: <y>}
或者使用经纬度坐标来定义位置信息。
<field>: { <field1>: <longitude>, <field2>: <latitude>}
与使用数组定义一致,经度定义在-180到180之间,包含-180和180两个数值。纬度在-90到90之间,同样包含两个边界。
地理信息索引
为了提高地理信息查询的性能,mongodb允许用户添加地理信息索引来时间数据的快速查询和计算。
二维空间索引
二维空间索引,支持曲面地理信息计算
用户使用db.collection.createIndex建立二维空间索引. 其中<location field>可以是一个坐标对或者GeoJSON类型的对象。
db.collection.createIndex( {<location field>: "2dsphere"})
二维平面索引
二维平面支持在两个维度的平面地理信息查询。尽管二维平面索引支持使用$nearSphere的空间查询,但用户在进行空间地理信息查询时,尽量使用二维空间索引。
用户使用db.collection.createIndex()方法,来创建二维平面索引。
db.collection.createIndex({<location field>: "2d"})
其中,<location field>字段是坐标对。
地理信息查询
用户使用二维平面索引查询时,mongdb可能会返回错误的数据或者报错。例如二维平面索引不支持跨越极点的查询 。
地理信息查询操作符
mongodb提供了4个操作符 ,用于查询地理信息。
|----------------|-------------|
| 操作符 | 描述 |
| $geoIntersects | 查询相交的地理信息数据 |
| $geoWithin | 查询包含的地理信息数据 |
| $near | 查询临近的平面地理对象 |
| $nearSphere | 查询临近的空间地理对象 |
聚合管道中的地理信息操作符
mongodb同样提供了一个应用在聚合管道中的地理信息操作符
|----------|--------------------------------------------------------------|
| 操作符 | 描述 |
| geoNear | 查询临近指定点的空间数据文档, 与match, $sort, $limit配合使用。输出文档包含了一个额外的距离字段。 |
地理信息模型
mongodb的地理信息查询可以在平面坐标系当中执行,也可以应用在空间查询当中。
使用二维空间索引时,只能进行空间当中的地理信息查询。而使用二维平面索引时,既可以进行平面空间查询,也可以进行部分空间查询。用户使用二维平面索引查询时,mongdb可能会返回错误的数据或者报错。下面的表格,列出了空间查询操作符所支持的查询空间类型和备注信息。
|------------------------------------|----------|
| 操作符 | 支持查询空间类型 |
| $near(使用GeoJSON对象进行查询,集合中包含2d空间索引) | 空间 |
| $near(使用坐标对象进行查询,集合中包含2d平面索引) | 平面 |
| $nearSphere(GeoJSON点,二维空间索引) | 空间 |
| $nearSphere(坐标点,二维平面索引) | 空间 |
| geoWithin: {geometry:...} | 空间 |
| geoWithin: {box:...} | 平面 |
| geoWithin: {polygon:...} | 平面 |
| geoWithin: {center:...} | 平面 |
| geoWithin: {centerSphere:...} | 空间 |
| geoIntersects | 空间 |
| 聚合管道中的geoNear, 带有二维空间索引 | 空间 |
| 聚合管道中的$geoNear, 带有二维平面索引 | 平面 |
应用
创建集合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.8308] },
category: "Stadiums"
}
]);
创建二维空间索引
db.places.createIndex({ location: "2dsphere" });
编写查询语句,要求查询出距离点{ type: "Point", coordinates: [-73.9667, 40.78]一公里到五公里范围内的兴趣点。
db.places.find({
location: {
$near: {
$geometry: { type: "Point", coordinates: [-73.9667, 40.78] },
$minDistance: 1000,
$maxDistance: 5000
}
}
});
构建管道查询,查询出点{ type: "Point", coordinates: [ -73.9667, 40.78 ] }附近的公园信息
db.places.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [-73.9667, 40.78] },
distanceField: "calcDistance",
query: { category: "Parks" },
spherical: true
}
}
]);