一、经纬度表示方式

MongoDB 中对经纬度的存储有着自己的一套规范(主要是为了可以在该字段上建立地理空间索引)。包括两种方式,分别是 Legacy Coordinate Pairs (这个词实在不知道怎么翻译...) 和  GeoJSON 。

  • Legacy Coordinate Pairs

Legacy Coordinate Pairs 又有两种方式可以存储经纬度,可以使用数组(首选)或嵌入式文档。

数组:

<field>: [<longitude>, <latitude> ]

嵌入式文档:

<field>: { <field1>: <longitude>, <field2>: <latitude> }

tips:有效经度值介于-180和180之间。有效纬度值介于-90和90之间。

  • GeoJSON

GeoJson 比 Legacy Coordinate Pairs 要强大的多,Legacy Coordinate Pairs 仅仅用来保存一个经纬度,而 GeoJson 可以用来指定点、线和多边形。

点可以用形如[longitude, latitude]([经度,纬度])的两个元素的数组表示:

{
"geometry": {
        "type": "Point",
        "coordinates": [125.6, 10.1]
   }
}

线可以用一个由点组成的数组来表示:

{
"geometry": {
        "type": "LineString",
         "coordinates": [[125.6, 10.1],[125.6,10.2],[125.6,10.3]]
   }
}

多边形的表示方式与线一样(都是一个由点组成的数组),但是"type"不同:

{
"geometry": {
        "type": "Polygon",
         "coordinates": [[125.6, 10.1],[125.5,10.2],[125.7,10.3]]
  }
}

type 除了 Point(点)、LineString(线)、Polygon(多边形),还有 MultiPoint(多点)、MultiLineString(多个线) 和  MultiPolygon(多个多边形)。

"geometry"字段的名字可以是任意的,但是其中的子对象是由GeoJSON指定的,不能改变。

二、地理空间索引

  • 2dsphere索引

2dsphere索引用于地球表面类型的地图,允许使用在 Legacy Coordinate Pairs 保存的经纬度字段上和使用GeoJSON格式保存的点、线和多边形字段上。

  db.world.ensureIndex({"geometry" : "2dsphere"})
  • 2d索引

对于非球面地图(游戏地图、时间连续的数据等),可以使用"2d"索引代替"2dsphere"。

2d 索引 仅允许使用在 Legacy Coordinate Pairs 保存的经纬度字段上。

  db.world.ensureIndex({"geometry" : "2d"})
  • 区别:

2dsphere索引只支持球形查询(即球面上几何图形的查询)。

2d索引支持平面查询(即在平面上几何图形的查询)和一些球形查询。虽然2d索引支持一些球形查询,但是对这些球形查询使用2d索引可能会导致错误,例如极点附近会出现大量的扭曲变形。
2d索引只能对点进行索引。可以保存一个由点组成的数组,但是它只会被保存为由点组成的数组,不会被当成线。特别是对于"$geoWithin"查询来说,这是一项重要的区别。如果将街道保存为由点组成的数组,那么如果其中的某个点位于给定的形状之内,这个文档就会与$geoWithin相匹配。但是,由这些点组成的线并不一定完全包含在这个形状之内。

三、地理空间查询

可以使用多种不同类型的地理空间查询:交集(intersection)、包含(within)以及接近(nearness)。

  • $geoIntersects

定义:指出与查询位置相交的文档。

支持的索引:2dsphere

几何操作符:

    1. $geometry (仅支持 2dsphere 索引,指定GeoJSON格式的几何图形)
  • $geoWithin

定义:指出完全包含在某个区域的文档。

支持的索引:2dsphere、2d

几何操作符:

  1. $box(仅支持 2d 索引,查询出矩形范围内的所有文档)
  2. $center(仅支持 2d 索引,查询出圆形范围内的所有文档)
  3. $polygon (仅支持 2d 索引,查询出多边形范围内的所有文档)
  4. $centerSphere(支持 2d 索引和 2dsphere 索引,查询出球面圆形范围内的所有文档)
  5. $geometry (仅支持 2dsphere 索引,指定GeoJSON格式的几何图形)
  • $near

定义:指出与查询位置从最近到最远的文档。

支持的索引:2dsphere、2d

几何操作符:

  1. $maxDistance (支持 2dsphere 索引和 2d 索引,指定查询结果的最大距离)
  2. $minDistance (仅支持 2dsphere 索引,指定查询结果的最小距离。在4.0后支持 2d 索引)
  3. $geometry (仅支持 2dsphere 索引,指定GeoJSON格式的点)

备注:$minDistance 官方文档说仅支持 2dsphere 索引,但是我实践证明 $minDistance 也支持 2d 索引,大家可以试试看,这里保留争议。

  • $nearSphere

定义:使用球面几何计算近球面的距离,指出与查询位置从最近到最远的文档。

支持的索引:2dsphere、2d

几何操作符:

  1. $maxDistance (支持 2dsphere 索引和 2d 索引,指定查询结果的最大距离)
  2. $minDistance (仅支持 2dsphere 索引,指定查询结果的最小距离。在4.0后支持 2d 索引)
  3. $geometry (仅支持 2dsphere 索引,指定GeoJSON格式的点)

备注:MongoDB 4.0 后对地理空间索引增加的支持?

1、地理空间查询操作符 $near 和 $nearSphere 支持查询的分片集合。

2、MongoDB 4.0 为 $geoNear 聚合运算符和 geoNear 命令添加了一个选项 key,使用户可以在查询时指定要使用的地理空间索引。以前,要使用 $geoNear 聚合运算符或 geoNear 命令,集合只能有一个地理空间索引。

db.places.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [ -73.98142 , 40.71782 ] },
key: "location",
distanceField: "dist.calculated",
query: { "category": "Parks" }
}
}
])

四、实践

  • "$geoIntersects" 操作符找出与查询位置相交的文档 ?
db.driverPoint.find(
{
coordinate: {
$geoIntersects: {
$geometry: {
type: "Polygon" ,
coordinates: [
[ [ 118.193828, 24.492242 ], [ 118.193953, 24.702114 ], [ 118.19387, 24.592242 ],[ 118.193828, 24.492242 ]]
]
}
}
}
}
)

tips:coordinates 表示多边形,第一个点 和 最后一个点 必须相同,因为这样才能拼成一个多边形呀!

  • "$geoWithin"操作符找出完全包含在某个区域的文档?
db.driverPoint.find(
{
coordinate: {
$geoWithin: {
$geometry: {
type: "Polygon" ,
coordinates: [
[ [ 118.193828, 24.492242 ], [ 118.193953, 24.702114 ], [ 119.19387, 28.792242 ],[ 118.193828, 24.492242 ]]
]
}
}
}
}
)
  • "$geoWithin"操作符找出矩形范围内的文档?
db.driverPoint.find(
{
coordinate: {
$geoWithin: {
$box: [
[ 118.0,24.0 ],
[ 120.0,30.0 ]
]
}
}
}
)

tips:"$box"接受一个两元素的数组:第一个元素指定左下角的坐标,第二个元素指定右上角的坐标。

  • "$geoWithin"操作符找出圆形范围内的文档?
db.driverPoint.find(
{
coordinate: {
$geoWithin: {
$center: [ [ 118.067678, 24.444373] , 10 ]
}
}
}
)

tips:"$center"接受一个两元素数组作为参数:第一个元素是一个点,用于指定圆心;第二个参数用于指定半径。

  • "$geoWithin"操作符找出多边形范围内的文档?
db.driverPoint.find(
{
coordinate: {
$geoWithin: {
$polygon: [ [ 118.067678 , 24.444373 ], [ 119.067678 , 25.444373 ], [ 120.067678 , 26.444373 ] ]
}
}
}
)

tips:"$polygon" 列表中的最后一个点会被连接到第一个点,以便组成多边形。

  • "$geoWithin"操作符找出球面圆形范围内的文档?
db.driverPoint.find(
{
coordinate: {
$geoWithin: {
$centerSphere: [ [ 118.067678, 24.444373 ], 10/3963.2 ]
}
}
}
)

tips:该例子表示 距离 [118.067678, 24.444373] 中心点10 英里范围内的所有文档,查询通过除以地球的大约赤道半径(3963.2英里)将距离转换为弧度。

  • $near 找出距离一个点相应距离内的文档?

geoJson 格式(仅支持 2dsphere 索引):

db.driverPoint.find(
{
coordinate: {
$near: {
$geometry: {
type: "Point" ,
coordinates: [ 118.067678 , 24.444373 ]
},
$maxDistance: 3000,
$minDistance: 0
}
}
}
)

Legacy Coordinate Pairs 格式(仅支持 2d 索引):

db.driverPoint.find(
{
coordinate: {
$near: [ 118.193828 , 24.492242 ],
$maxDistance: 0.10
}
}
)

tips:1、$near 当用 geoJson 格式表示时, 距离单位是米(meter)。

2、$near 当用 Legacy Coordinate Pairs 格式表示时,距离单位是弧度(radian)。

3、"$near"是唯一一个会对查询结果进行自动排序的地理空间操作符:"$near"的返回结果是按照距离由近及远排序的。

五、结语

怎么说呢?学习这方面的知识老是给我一种特别乱的感觉。稍微总结下吧!MongoDB 对于地理空间的查询 是基于 它对 地理空间的索引(即2dsphere 和 2d)来实现的。所以,我们只要搞清楚什么时候 该建立 2dsphere 索引,什么时候该建立 2d 索引,然后再找适用于该索引的操作符就很清晰明了了!总之,geoJSON 格式保存的经纬度一定 建立 2dsphere 索引。Legacy Coordinate Pairs 格式保存的经纬度 仅在表示 平面地图的时候才考虑建立 2d 索引,其他情况还是选择 2dsphere 索引。

Spring Data MongoDB 中对地理位置的查询可参考 https://github.com/JMCuixy/SpringDataMongoDB 中单元测试的 Test03.java。

参考资料:

1、《MongoDB 权威指南第二版》

2、https://docs.mongodb.com/manual/reference/operator/query-geospatial/

MongoDB系列五(地理空间索引与查询).的更多相关文章

  1. MongoDB小结26 - 地理空间索引

    现在有一种查询变得越来越流行(尤其是移动设备):找到离当前位置最近的N个场所. MongoDB专为平面坐标查询做了专门的索引,称为地理空间索引. 同样需要用ensureIndex创建,不过,参数是两个 ...

  2. ElasticSearch实战系列五: ElasticSearch的聚合查询基础使用教程之度量(Metric)聚合

    Title:ElasticSearch实战系列四: ElasticSearch的聚合查询基础使用教程之度量(Metric)聚合 前言 在上上一篇中介绍了ElasticSearch实战系列三: Elas ...

  3. 全文索引&&地理空间索引

    Ⅰ.全文索引 搜索引擎的实现核心技术,搜索类似where col like '%xxx%';关键字可以出现再某个列任何位置 这种查询条件,B+ tree索引是无法使用的.如果col上创建了索引,因为排 ...

  4. 6.MongoDB系列之特殊索引和集合类型

    1. 地理空间索引及全文搜索 与Elasitcsearch一样,MongoDB同样支持地理空间索引及全文搜索,由于选型常用ES而非MongoDB此处略过 2. TTL索引 首先先了解下固定集合,其类似 ...

  5. 玩转mongodb(七):索引,速度的引领(全文索引、地理空间索引)

    本篇博文主要介绍MongoDB中一些常用的特殊索引类型,主要包括: 用于简单字符串搜索的全文本索引: 用于球体空间(2dsphere)和二维平面(2d)的地理空间索引. 一.全文索引 MongoDB有 ...

  6. MongoDB 学习笔记之 地理空间索引入门

    地理空间索引: 地理空间索引,可用于处理基于地理位置的查询. Point:用于指定所在的具体位置,我们以restaurants为例: db.restaurants.insert({name: &quo ...

  7. Mongodb地理空间索引

    1.索引: 建立索引既耗时也费力,还需要消耗很多资源.使用{"bakckground":true}选项可以使这个过程在后台完成,同时正常处理请求.如果不包括background 这 ...

  8. mongodb的地理空间索引常见的问题

    创建地理空间索引注意事项 创建地理空间索引失败,提示错误信息如下 > db.places.ensureIndex({"loc":"2dsphere"}){ ...

  9. MongoDB系列一(查询).

    一.简述 MongoDB中使用find来进行查询.查询就是返回一个集合中文档的子集,子集合的范围从0个文档到整个集合.默认情况下,"_id"这个键总是被返回,即便是没有指定要返回这 ...

随机推荐

  1. Mysql设置字段自动获取时间

    问题:现在在用户表中有一个字段表示用户创建的时间 第一个想法是写一段程序获得系统当前时间,想想就太麻烦了,果断放弃,之后想到了存储过程和函数,再想想还要编写存储过程或者函数的代码,有点放弃的想法,但是 ...

  2. JavaSE中常见的工具类

    Arrays 用来操作数组, 常用方法是 sort()和toString()方法 Iterator 我们常说的迭代器就是这哥们,专门用来操作集合元素的工具类 常用方法是: hasNex()t和next ...

  3. 笔记:Hibernate 数据库方言表

    关系数据库 方言 DB2 org.hibernate.dialect.DB2Dialect DB2 AS/400 org.hibernate.dialect.DB2400Dialect DB2 OS/ ...

  4. 如何防止cookie被串改

    在这里我不想多说怎么去操作cookie了,网上博文一大堆,大家可以去自行搜索,在这里也是记录一下自己的知识,以便以后方便查阅.当我们在浏览器地址栏输入地址成功打开网页以后,服务器会把一些信息写入coo ...

  5. Maven学习笔记一

    maven是apache下的一个开源项目,是纯java开发,并且只是用来管理java项目的. Maven好处 1.普通的传统项目,包含jar包,占用空间很大.而Maven项目不包含jar包,所以占用空 ...

  6. 【前端】wangEditor(富文本编辑器) 简易使用示例

    转载请说明作者或者注明出处,谢谢 说到前端常用的编辑器,自然也少不了富文本编辑器(RichText Editor) 笔者在此之前也看了一些相关的在线编辑器,其中包括了当百度搜索“富文本编辑器”字样时出 ...

  7. PTA的使用简介

    PTA(Programming Teaching Assistant)是PAT(Programming Ability Test)的配套练习平台. 1.关于PAT PAT(Programming Ab ...

  8. C语言第二周作业——分支结构

    一.PTA实验作业 题目1.7-1计算分段函数 本题目要求计算下列分段函数f(x)的值: 1实验代码 double x,result; scanf("%lf",&x); i ...

  9. 敏捷冲刺每日报告--day2

      1 团队介绍 团队组成: PM:齐爽爽(258) 小组成员:马帅(248),何健(267),蔡凯峰(285)  Git链接:https://github.com/WHUSE2017/C-team ...

  10. 个人作业2:QQ音乐APP案例分析

    APP案例分析 QQ音乐 选择理由:毕竟作为QQ音乐九年的资深老用户以及音乐爱好者 第一部分 调研 1.第一次上手的体验    我算是很早期的QQ音乐的用户,用QQ音乐七八年,除了体验各方面还不错之外 ...