578 lines
20 KiB
Markdown
578 lines
20 KiB
Markdown
|
---
|
|||
|
title: MongoDB中的空间索引
|
|||
|
date: 2021-01-21
|
|||
|
author: ac
|
|||
|
tags:
|
|||
|
- MongoDB
|
|||
|
- geojson
|
|||
|
categories:
|
|||
|
- Database
|
|||
|
---
|
|||
|
|
|||
|
> 为了支持对地理空间坐标数据的高效查询,MongoDB提供了两个特殊的索引:2d索引(返回结果时使用平面几何)和2dsphere索引(返回结果时使用球面几何)。
|
|||
|
|
|||
|
### 1. `MongoDB`中的地理空间数据
|
|||
|
|
|||
|
在`MongoDB`中,用文档记录地球球体(地理坐标)上的位置信息,可以将数据存储为`GeoJSON`对象,如果用文档记录几何平面(投影坐标)上的位置信息,可以将数据存储为`legacy coordinate pairs`传统坐标对。
|
|||
|
|
|||
|
> `mongodb`对地理坐标的`GeoJSON`对象进行的空间查询操作,使用的空间参考是`WGS84`。
|
|||
|
|
|||
|
#### 1.1 [GeoJSON](https://tools.ietf.org/html/rfc7946#section-3.1)对象
|
|||
|
|
|||
|
`GeoJSON`是一种基于`JSON`格式的地理空间数据交换格式。它定义了几种类型的`JSON`对象,通过这些`JSON`对象或其组合来表示地理空间数据的特征、性质和空间范围等信息。
|
|||
|
|
|||
|
`GeoJSON`默认使用的是地理坐标参考系统(`WGS-84`),单位是十进制的度。
|
|||
|
|
|||
|
一个`GeoJSON`对象可以是[SFSQL](https://www.ogc.org/standards/sfs)规范中定义的七种几何类型(`Point`、`MultiPoint`、`LineString`、`MultiLineString`,`Polygon`,`MultiPolygon`,`GeometryCollection`)。
|
|||
|
|
|||
|
`GeoJSON`表示的这些几何类型与`WKT`和`WKB`的很相似。
|
|||
|
|
|||
|
```json
|
|||
|
//WKT:Point(102.0, 0.5)对应下面的geojson
|
|||
|
{
|
|||
|
"type": "Point",
|
|||
|
"coordinates": [102.0, 0.5]
|
|||
|
}
|
|||
|
|
|||
|
//WKT:LineString(102.0 0.0,103.0 1.0,104.0 0.0)
|
|||
|
{
|
|||
|
"type":"LineString",
|
|||
|
"coordinates": [
|
|||
|
[102.0, 0.0],
|
|||
|
[103.0, 1.0],
|
|||
|
[104.0, 0.0],
|
|||
|
]
|
|||
|
}
|
|||
|
/*
|
|||
|
* WKT:
|
|||
|
Polygon(
|
|||
|
(100.0 0.0,101.0 0.0,101.0 1.0,100.0 1.0,100.0 0.0)
|
|||
|
)
|
|||
|
*/
|
|||
|
{
|
|||
|
"type": "Polygon",
|
|||
|
"coordinates": [
|
|||
|
[
|
|||
|
[100.0, 0.0],
|
|||
|
[101.0, 0.0],
|
|||
|
[101.0, 1.0],
|
|||
|
[100.0, 1.0],
|
|||
|
[100.0, 0.0]
|
|||
|
]
|
|||
|
]
|
|||
|
}
|
|||
|
/**
|
|||
|
*WKT:
|
|||
|
MultiPoint((100.0 0.0),(101.0 1.0))
|
|||
|
*/
|
|||
|
{
|
|||
|
"type": "MultiPoint",
|
|||
|
"coordinates": [
|
|||
|
[100.0, 0.0],
|
|||
|
[101.0, 1.0]
|
|||
|
]
|
|||
|
}
|
|||
|
/**
|
|||
|
*WKT:
|
|||
|
MultiLineString((100.0 0.0,101.0 1.0),(102.0 2.0,103.0 3.0))
|
|||
|
*/
|
|||
|
{
|
|||
|
"type": "MultiLineString",
|
|||
|
"coordinates": [
|
|||
|
[
|
|||
|
[100.0, 0.0],
|
|||
|
[101.0, 1.0]
|
|||
|
],
|
|||
|
[
|
|||
|
[102.0, 2.0],
|
|||
|
[103.0, 3.0]
|
|||
|
]
|
|||
|
]
|
|||
|
}
|
|||
|
/**WTK:
|
|||
|
*MultiPolygon(
|
|||
|
((102.0 2.0,103.0 2.0,103.0 3.0,102.0 3.0,102.0 2.0)),
|
|||
|
(
|
|||
|
(100.0 0.0,101.0 0.0,100.1 1.0,100.0 1.0,100.0 0.0),
|
|||
|
(100.2 0.2,100.2 0.8,100.8 0.8,100.8 0.2,100.2 0.2)
|
|||
|
)
|
|||
|
)
|
|||
|
*/
|
|||
|
{
|
|||
|
"type": "MultiPolygon",
|
|||
|
"coordinates": [
|
|||
|
[
|
|||
|
[
|
|||
|
[102.0, 2.0],
|
|||
|
[103.0, 2.0],
|
|||
|
[103.0, 3.0],
|
|||
|
[102.0, 3.0],
|
|||
|
[102.0, 2.0]
|
|||
|
]
|
|||
|
],
|
|||
|
[
|
|||
|
[
|
|||
|
[100.0, 0.0],
|
|||
|
[101.0, 0.0],
|
|||
|
[101.0, 1.0],
|
|||
|
[100.0, 1.0],
|
|||
|
[100.0, 0.0]
|
|||
|
],
|
|||
|
[
|
|||
|
[100.2, 0.2],
|
|||
|
[100.2, 0.8],
|
|||
|
[100.8, 0.8],
|
|||
|
[100.8, 0.2],
|
|||
|
[100.2, 0.2]
|
|||
|
]
|
|||
|
]
|
|||
|
]
|
|||
|
}
|
|||
|
/**WKT:
|
|||
|
*GeometryCollection(
|
|||
|
POINT(100.0 0.0),
|
|||
|
LINESTRING(101.0 0.0,102.0 1.0)
|
|||
|
)
|
|||
|
*/
|
|||
|
{
|
|||
|
"type": "GeometryCollection",
|
|||
|
"geometries": [{
|
|||
|
"type": "Point",
|
|||
|
"coordinates": [100.0, 0.0]
|
|||
|
}, {
|
|||
|
"type": "LineString",
|
|||
|
"coordinates": [
|
|||
|
[101.0, 0.0],
|
|||
|
[102.0, 1.0]
|
|||
|
]
|
|||
|
}]
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
在`SFSQL`中,`coordinate`是一`n`个数字组成的数组,用来表示`n`维空间下点`Point`的位置信息。`Geometry Object`都有一个`coordinates`属性来表示几何体中的点位信息。
|
|||
|
|
|||
|
需要注意的是`Polygon`类型的`GeoJSON`对象,`Polygon`是由`Linearing`数组构成,第一个`Linearing`是面的外边界(`Exterior boundary`),其余的为面内的“洞”(`Interior boundary`),且不能相交或重叠,也不能共享边界。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
> `LinearRing`是一段封闭的分段的线状路径,(coordinates 的成员数组)至少4个坐标点,三个坐标可以确定 `LinearRing`,第四个坐标用于闭合,与第一个坐标相同。
|
|||
|
>
|
|||
|
> 一个`LinearRing`必须遵循右手定则,**外边界是逆时针的,而“洞”是顺时针方向**。
|
|||
|
|
|||
|
|
|||
|
|
|||
|
另外,`GeoJSON`的类型还包括`Feature`和`FeatureCollection`两种。
|
|||
|
|
|||
|
`Feature`类型的`GeoJSON`对象必须包含一个`geometry`属性,且值为上述几何类型中的一种,及其它属性`perproties`。`FeatureCollection`包含一个`Feature`数组对象。
|
|||
|
|
|||
|
```
|
|||
|
Feature
|
|||
|
↙ ↘
|
|||
|
Geometry properties
|
|||
|
↙ ↓ ↘
|
|||
|
Point Polyline Polygon
|
|||
|
MultiPoint MultiLineString MultiPolygon
|
|||
|
GeometryCollection
|
|||
|
```
|
|||
|
|
|||
|
示例:
|
|||
|
|
|||
|
`Feature`类型的`GeoJSON`:
|
|||
|
|
|||
|
```json
|
|||
|
{
|
|||
|
"type": "Feature",
|
|||
|
"properties": {
|
|||
|
"name": "测试点"
|
|||
|
},
|
|||
|
"geometry": {
|
|||
|
"type": "Point",
|
|||
|
"coordinates": [
|
|||
|
113.95560264587402,
|
|||
|
22.51267588902413
|
|||
|
]
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
`FeatureCollection`类型的`GeoJSON`:
|
|||
|
|
|||
|
```json
|
|||
|
{
|
|||
|
"type": "FeatureCollection",
|
|||
|
"features": [
|
|||
|
{
|
|||
|
"type": "Feature",
|
|||
|
"properties": {
|
|||
|
"name": "测试线"
|
|||
|
},
|
|||
|
"geometry": {
|
|||
|
"type": "LineString",
|
|||
|
"coordinates": [
|
|||
|
[
|
|||
|
113.96212577819824,
|
|||
|
22.515649230084094
|
|||
|
],
|
|||
|
[
|
|||
|
113.96092414855956,
|
|||
|
22.49241582330295
|
|||
|
]
|
|||
|
]
|
|||
|
}
|
|||
|
},
|
|||
|
{
|
|||
|
"type": "Feature",
|
|||
|
"properties": {
|
|||
|
"name": "测试点"
|
|||
|
},
|
|||
|
"geometry": {
|
|||
|
"type": "Point",
|
|||
|
"coordinates": [
|
|||
|
113.95560264587402,
|
|||
|
22.51267588902413
|
|||
|
]
|
|||
|
}
|
|||
|
}
|
|||
|
]
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
`GeoJSON`的类型是**【不可扩展】**的,只有固定的上面简述的九种。其中`FeatureCollection`是最常用的一种,像`WFS`服务,将响应格式设为`application/json`时,服务就会返回一个`FeatureCollection`类型的`GeoJSON`对象。
|
|||
|
|
|||
|
>
|
|||
|
> 注意:"geometry type" 的值是大小写敏感的。
|
|||
|
>
|
|||
|
|
|||
|
`MongoDB`中支持的`GeoJSON`对象类型只有上述简述的[SFSQL](https://www.ogc.org/standards/sfs)规范中的七种`geometry type`。文档存储`GeoJSON`对象数据,通常是作为属性值嵌入到文档中,格式如下:
|
|||
|
|
|||
|
```json
|
|||
|
<field>:{
|
|||
|
type:<GeoJSON type>,
|
|||
|
coordinates:<coordinates>
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
- 必须有一个`type`属性,且值为`GeoJSON object type`
|
|||
|
- 必须有一个`coordinates`属性,用于表示几何对象的点位信息。
|
|||
|
|
|||
|
如果`coordinates`是经纬度的地理坐标,则其有效的经度值在-180到180之间,两者都包括在内,有效的纬度在-90到90之间。
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#### 1.2 Legacy Coordinate Pairs
|
|||
|
|
|||
|
对于平面坐标,建议是存储成`Legacy Coordinate Pairs`坐标对,可以使用`2d`索引。
|
|||
|
|
|||
|
存储坐标对数据可以使用数组或嵌入文档的形式:
|
|||
|
|
|||
|
```json
|
|||
|
//数组(优先考虑)
|
|||
|
<field>: [<x>, <y>]
|
|||
|
或
|
|||
|
<field>: [<longitude>, <latitude>]
|
|||
|
```
|
|||
|
|
|||
|
```json
|
|||
|
//嵌入文档
|
|||
|
<field>: { <field1>: <x>, <field2>: <y> }
|
|||
|
或
|
|||
|
<field>: { <field1>: <longitude>, <field2>: <latitude> }
|
|||
|
```
|
|||
|
|
|||
|
从上面的结构可以看出,坐标对的形式其实只适合存储`Point`类型的数据。
|
|||
|
|
|||
|
|
|||
|
|
|||
|
### 2. 地理空间索引
|
|||
|
|
|||
|
**地理空间索引(`Geospatial Index`)**
|
|||
|
|
|||
|
为了支持对地理空间坐标数据的有效查询,`MongoDB`提供了两种特殊的索引:使用平面几何数据(投影坐标)的**二维索引(2d indexes)**和使用球面几何(地理坐标)数据的**二维球面索引(2dsphere indexes)**。
|
|||
|
|
|||
|
#### 2.1 `2dsphere indexes`
|
|||
|
|
|||
|
`2dsphere`索引支持在地球球体上的几何计算和支持所有`MongoDB`地理空间查询(包含,相交和接近等)。
|
|||
|
|
|||
|
`2dsphere`索引支持存储为`GeoJSON`对象和传统坐标对的数据。但对于传统坐标对,索引需要将数据转换为`GeoJSON`中的点类型。
|
|||
|
|
|||
|
**创建`2dsphere`索引**
|
|||
|
|
|||
|
创建一个`2dsphere`索引,可以使用`db.collection.createIndex()`方法,指定索引类型为`2dsphere`:
|
|||
|
|
|||
|
```shell
|
|||
|
//单字段索引
|
|||
|
db.collection.createIndex({<location field>: "2dsphere"})
|
|||
|
```
|
|||
|
|
|||
|
其中的`<location field>`字段的值应为`GeoJSON`对象或`legacy coordinates pair`传统坐标对。如果在`2dsphere`索引字段中插入带有非几何数据的文档,或者在集合中的非几何数据的字段上构建`2dsphere`索引,则会操作失败(索引字段的限制)。
|
|||
|
|
|||
|
创建包含`2dsphere`索引的复合索引,可以包含多个位置信息的几何字段和非地理空间信息的字段:
|
|||
|
|
|||
|
```shell
|
|||
|
//复合索引
|
|||
|
db.sphere.createIndex({"location":"2dsphere","name":1})
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#### 2.2 `2d indexes`
|
|||
|
|
|||
|
`2d indexes`支持平面几何上的计算和查询,虽然该索引支持通过`$nearSphere`查询球面上的几何计算,但对于球面上的计算,还是尽可能的使用`2dsphere`索引。
|
|||
|
|
|||
|
**创建`2d`索引**
|
|||
|
|
|||
|
创建一个`2d`索引,可以使用`db.collection.ceateIndex()`方法,指定索引类型为`2d`:
|
|||
|
|
|||
|
```shell
|
|||
|
db.collection.createIndex( { <location field> : "2d" } )
|
|||
|
```
|
|||
|
|
|||
|
索引字段`location field`的值必须是`legacy coordinates pair`
|
|||
|
|
|||
|
|
|||
|
|
|||
|
### 3. 空间查询
|
|||
|
|
|||
|
> `MongoDB`中的空间查询是基于空间索引基础之上的,所以进行空间查询前,因先创建地理空间索引。
|
|||
|
|
|||
|
#### 3.1 查询操作
|
|||
|
|
|||
|
`MongoDB`提供以下空间查询操作:
|
|||
|
|
|||
|
| name | Description |
|
|||
|
| ---------------- | ------------------------------------------------------------ |
|
|||
|
| `$geoIntersects` | 查询几何对象与指定的`GeoJSON`对象相交的文档。`2dsphere` 索引支持该操作。 |
|
|||
|
| `$geoWithin` | 查询几何对象在指定的`GeoJSON`对象边界内的文档。`2dsphere`和`2d`索引都支持该操作。 |
|
|||
|
| `$near` | 返回几何对象在指定点附近的文档。`2dsphere`和`2d`索引都支持该操作。 |
|
|||
|
| `$nearSphere` | 返回球体上某点附近的地理空间对象文档。`2dsphere`和`2d`索引都支持该操作。 |
|
|||
|
|
|||
|
#### 3.2 几何操作符
|
|||
|
|
|||
|
| name | Description | format |
|
|||
|
| --------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
|||
|
| `$box` | 在`$geoWithin`操作中使用传统坐标对(`legacy coordinate pairs`)指定矩形,只有`2d index`支持。 | { \<location field>: { $geoWithin: { $box: [ [ \<bottom left coordinates> ], [ \<upper right coordinates> ] ] } } } |
|
|||
|
| `$center` | 在`$geoWithin`操作中使用传统坐标对(`legacy coordinate pairs`)指定圆形,只有`2d index`支持。 | { \<location field>: { $geoWithin: { $center: [ [ \<x>,\<y> ] , \<radius> ] } } } |
|
|||
|
| `$centerSphere` | 当使用球面几何的地理空间查询时,在`$geoWithin`操作中使用传统坐标对或`GeoJSON`对象,`2d `和`2dsphere`都支持 | { \<location field>: { $geoWithin: { $centerSphere: [ [\<x>, \<y> ], \<radius> ] } } } |
|
|||
|
| `$geometry` | 用于在空间查询操作中使用`GeoJSON`对象指定输入的几何对象。`2d `和`2dsphere`都支持。 | $geometry: { type: "\<GeoJSON object type>", coordinates: [ \<coordinates> ] } |
|
|||
|
| `$maxDistance` | 用于过滤`$near`和`$nearSphere`查询结果,指定最大距离。单位由坐标系决定(对于`GeoJSON`的点对象使用米为单位)。`2d `和`2dsphere`都支持。 | db.places.find( { loc: { $near: [ -74 , 40 ], $maxDistance: 10 } } ) |
|
|||
|
| `$minDistance` | 用于过滤`$near`和`$nearSphere`操作的查询结果,限定结果文档中的几何对象到中心点的最小距离。`2d `和`2dsphere`索引都支持。 | db.places.find( { location: { $nearSphere: { $geometry: { type : "Point", coordinates : [ -73.9667, 40.78 ] }, $minDistance: 1000, $maxDistance: 5000 }} } ) |
|
|||
|
| `$polygon` | 为`$geoWithin`查询指定一个使用传统坐标对的多边形。只有`2d`索引支持该操作。 | db.places.find( { loc: { $geoWithin: { $polygon: [ [ 0 , 0 ], [ 3 , 6 ], [ 6 , 0 ] ] } } } ) |
|
|||
|
| `$uniqueDocs` | 地理空间查询不返回重复的结果。从2.6开始就被废弃了,`$uniqueDocs`操作符对结果没有影响。 | |
|
|||
|
|
|||
|
`$geoIntersects`操作使用`$geometry`指定`GeoJSON`对象
|
|||
|
|
|||
|
```shell
|
|||
|
|
|||
|
{
|
|||
|
<location field>: {
|
|||
|
$geoIntersects: {
|
|||
|
$geometry: {
|
|||
|
type: "<GeoJSON object type>" ,
|
|||
|
coordinates: [ <coordinates> ]
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
`$geoWithin`操作也是使用`$geometry`指定一个`Polygon`或`MultiPolygon`类型的`GeoJSON`对象作为输入:
|
|||
|
|
|||
|
```json
|
|||
|
{
|
|||
|
<location field>: {
|
|||
|
$geoWithin: {
|
|||
|
$geometry: {
|
|||
|
type: <"Polygon" or "MultiPolygon"> ,
|
|||
|
coordinates: [ <coordinates> ]
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
`$near`操作与`$maxDistance`和`$minDistance`操作符一起使用,返回以指定点为中心点,在限定距离范围内的文档。`$near`操作的输入可以是`GeoJSON`格式的数据也可以是坐标对的数据,对空间索引的要求有区别:
|
|||
|
|
|||
|
- 对`GeoJSON`类型的点,需要使用`2dsphere`索引
|
|||
|
- 对坐标对格式的点数据,需要使用`2d`索引
|
|||
|
|
|||
|
```json
|
|||
|
//GeoJSON Point,unit is meters
|
|||
|
{
|
|||
|
<location field>: {
|
|||
|
$near: {
|
|||
|
$geometry: {
|
|||
|
type: "Point" ,
|
|||
|
coordinates: [ <longitude> , <latitude> ]
|
|||
|
},
|
|||
|
$maxDistance: <distance in meters>,
|
|||
|
$minDistance: <distance in meters>
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
// legacy coordinates,unit is radians
|
|||
|
{
|
|||
|
$near: [ <x>, <y> ],
|
|||
|
$maxDistance: <distance in radians>
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
`$nearSphere`操作是针对地理坐标进行计算的,返回指定球面上距离中心点在某段范围内的文档。当然,地理坐标您可以存储为`GeoJSON`的格式,也可以存储为传统坐标对的形式。
|
|||
|
|
|||
|
- 当文档中的几何数据格式是`GeoJSON`时,建议使用`GeoJSON`类型的点作为输入,且使用`2dsphere`索引;
|
|||
|
- 当文档中的位置信息格式是传统坐标对时,使用传统坐标对作为输入,且使用`2d`索引。其实`$nearSphere`操作也可以在`GeoJSON`格式的数据上使用`2d`索引。
|
|||
|
|
|||
|
```json
|
|||
|
//GeoJSON 格式输入,单位为米
|
|||
|
{
|
|||
|
$nearSphere: {
|
|||
|
$geometry: {
|
|||
|
type : "Point",
|
|||
|
coordinates : [ <longitude>, <latitude> ]
|
|||
|
},
|
|||
|
$minDistance: <distance in meters>,
|
|||
|
$maxDistance: <distance in meters>
|
|||
|
}
|
|||
|
}
|
|||
|
//传统坐标对格式输入,单位为弧度
|
|||
|
{
|
|||
|
$nearSphere: [ <x>, <y> ],
|
|||
|
$minDistance: <distance in radians>,
|
|||
|
$maxDistance: <distance in radians>
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#### 3.3 实例
|
|||
|
|
|||
|
##### 数据准备
|
|||
|
|
|||
|

|
|||
|
|
|||
|
```shell
|
|||
|
> use geodata
|
|||
|
switched to db geodata
|
|||
|
> db.sphere.insert(
|
|||
|
{"name":"测试点","location":{"type": "Point","coordinates": [113.92024040222168,22.548708470991805]}})
|
|||
|
|
|||
|
> db.sphere.insert(
|
|||
|
{"name":"线段1","location":{"type": "LineString","coordinates": [[113.92993927001953,22.535707699328004],[113.91483306884766,22.504310546471817]]}})
|
|||
|
|
|||
|
> db.sphere.insert(
|
|||
|
{"name":"线段2","location":{"type": "LineString","coordinates": [[113.92204284667969,22.572487200676317],[113.99070739746094,22.518265717308317]]}})
|
|||
|
|
|||
|
> db.sphere.insert(
|
|||
|
{"name": "线段3","location":{"type": "LineString","coordinates": [[113.97457122802734,22.562976200808055],[113.9725112915039,22.484644051870895]]}})
|
|||
|
|
|||
|
> db.sphere.insert(
|
|||
|
{"name": "面1","location":{"type": "Polygon","coordinates": [[[113.89663696289062,22.581997544284242],[113.89869689941406,22.53507348402533],[113.90865325927733,22.491940013104305],[113.95397186279297,22.554098675696263],[113.89663696289062,22.581997544284242]]]}})
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
##### 创建`2dsphere`索引
|
|||
|
|
|||
|
```shell
|
|||
|
> db.sphere.createIndex({"location":"2dsphere"})
|
|||
|
{
|
|||
|
"createdCollectionAutomatically" : false,
|
|||
|
"numIndexesBefore" : 1,
|
|||
|
"numIndexesAfter" : 2,
|
|||
|
"ok" : 1
|
|||
|
}
|
|||
|
> db.sphere.getIndexes()
|
|||
|
[
|
|||
|
{
|
|||
|
"v" : 2,
|
|||
|
"key" : {
|
|||
|
"_id" : 1
|
|||
|
},
|
|||
|
"name" : "_id_"
|
|||
|
},
|
|||
|
{
|
|||
|
"v" : 2,
|
|||
|
"key" : {
|
|||
|
"location" : "2dsphere"
|
|||
|
},
|
|||
|
"name" : "location_2dsphere",
|
|||
|
"2dsphereIndexVersion" : 3
|
|||
|
}
|
|||
|
]
|
|||
|
```
|
|||
|
|
|||
|
##### 空间查询操作
|
|||
|
|
|||
|
使用线段2作为输入,执行`geoIntersects`操作:
|
|||
|
|
|||
|
```shell
|
|||
|
> db.sphere.find({location:{
|
|||
|
... $geoIntersects: {
|
|||
|
... $geometry: {
|
|||
|
... "type": "LineString",
|
|||
|
... "coordinates": [
|
|||
|
... [113.92204284667969,22.572487200676317],
|
|||
|
... [113.99070739746094,22.518265717308317]
|
|||
|
... ]
|
|||
|
... }
|
|||
|
... }
|
|||
|
... }})
|
|||
|
{ "_id" : ObjectId("600f9a8d264f9b09033f1fe7"), "name" : "线段2", "location" : { "type" : "LineString", "coordinates" : [ [ 113.92204284667969, 22.572487200676317 ], [ 113.99070739746094, 22.518265717308317 ] ] } }
|
|||
|
{ "_id" : ObjectId("600f9a9f264f9b09033f1fe9"), "name" : "面1", "location" : { "type" : "Polygon", "coordinates" : [ [ [ 113.89663696289062, 22.581997544284242 ], [ 113.89869689941406, 22.53507348402533 ], [ 113.90865325927733, 22.491940013104305 ], [ 113.95397186279297, 22.554098675696263 ], [ 113.89663696289062, 22.581997544284242 ] ] ] } }
|
|||
|
{ "_id" : ObjectId("600f9a98264f9b09033f1fe8"), "name" : "线段3", "location" : { "type" : "LineString", "coordinates" : [ [ 113.97457122802734, 22.562976200808055 ], [ 113.9725112915039, 22.484644051870895 ] ] } }
|
|||
|
>
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
使用面1作为输入,执行`$geoWithin`操作
|
|||
|
|
|||
|
```shell
|
|||
|
> db.sphere.find({location:{$geoWithin: {$geometry: {"type": "Polygon","coordinates": [[[113.89663696289062,22.581997544284242],[113.89869689941406,22.53507348402533],[113.90865325927733,22.491940013104305],[113.95397186279297,22.554098675696263],[113.89663696289062,22.581997544284242]]]}}}})
|
|||
|
|
|||
|
{ "_id" : ObjectId("600f9a9f264f9b09033f1fe9"), "name" : "面1", "location" : { "type" : "Polygon", "coordinates" : [ [ [ 113.89663696289062, 22.581997544284242 ], [ 113.89869689941406, 22.53507348402533 ], [ 113.90865325927733, 22.491940013104305 ], [ 113.95397186279297, 22.554098675696263 ], [ 113.89663696289062, 22.581997544284242 ] ] ] } }
|
|||
|
{ "_id" : ObjectId("600f9a0c264f9b09033f1fe6"), "name" : "线段1", "location" : { "type" : "LineString", "coordinates" : [ [ 113.92993927001953, 22.535707699328004 ], [ 113.91483306884766, 22.504310546471817 ] ] } }
|
|||
|
{ "_id" : ObjectId("600f92c5264f9b09033f1fe5"), "name" : "测试点", "location" : { "type" : "Point", "coordinates" : [ 113.92024040222168, 22.548708470991805 ] } }
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
使用测试点作为输入,执行`$nearSphere`操作。结果会按距离中心点距离,由远到近进行排序。
|
|||
|
|
|||
|
```shell
|
|||
|
db.sphere.find({
|
|||
|
location:{
|
|||
|
$nearSphere:{
|
|||
|
$geometry:{
|
|||
|
type:"Point",
|
|||
|
coordinates:[113.92024040222168,22.548708470991805]
|
|||
|
},
|
|||
|
$minDistance: 100,
|
|||
|
$maxDistance: 10000
|
|||
|
}
|
|||
|
}
|
|||
|
})
|
|||
|
{ "_id" : ObjectId("600f9a0c264f9b09033f1fe6"), "name" : "线段1", "location" : { "type" : "LineString", "coordinates" : [ [ 113.92993927001953, 22.535707699328004 ], [ 113.91483306884766, 22.504310546471817 ] ] } }
|
|||
|
{ "_id" : ObjectId("600f9a8d264f9b09033f1fe7"), "name" : "线段2", "location" : { "type" : "LineString", "coordinates" : [ [ 113.92204284667969, 22.572487200676317 ], [ 113.99070739746094, 22.518265717308317 ] ] } }
|
|||
|
{ "_id" : ObjectId("600f9a98264f9b09033f1fe8"), "name" : "线段3", "location" : { "type" : "LineString", "coordinates" : [ [ 113.97457122802734, 22.562976200808055 ], [ 113.9725112915039, 22.484644051870895 ] ] } }
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
### 参考文章
|
|||
|
|
|||
|
[1] `2d Index Internals` https://docs.mongodb.com/manual/core/geospatial-indexes/
|
|||
|
|
|||
|
[2] `The GeoJSON Format` https://tools.ietf.org/html/rfc7946#section-3.1
|
|||
|
|
|||
|
[3] `GeoJSON Objects` https://docs.mongodb.com/manual/reference/geojson/
|
|||
|
|
|||
|
[4] `Simple Feature Access - Part 2: SQL Option` https://www.ogc.org/standards/sfs
|
|||
|
|
|||
|
[5] `Geospatial Query Operators` https://docs.mongodb.com/manual/reference/operator/query-geospatial/
|