MongoDB 地理空间查询

本章介绍以下几点:

  • 地理空间数据
  • 地理空间索引
  • 地理空间查询
  • 地理空间模型
  • 例子

MongoDB支持对地理空间数据的查询操作。本节介绍MongoDB的地理空间特性。

1.地理空间数据

在MongoDB中,可以将地理空间数据存储为GeoJSON对象或遗留坐标对。

1.1 GeoJSON对象

要计算类地球体上的几何形状,请将位置数据存储为GeoJSON对象。

要指定GeoJSON数据,请使用带有以下内容的嵌入式文档:

  • 指定GeoJSON对象类型的名为type的字段和
  • 指定对象坐标的名为coordinates的字段。

如果指定经纬度坐标,首先列出经度,然后是纬度:

  • 有效经度值在-180和180之间,两者都包括在内。
  • 有效纬度值在-90和90之间,两者都包括在内。
: { type:  , coordinates:  }

例如,要指定一个GeoJSON点:

location: {
      type: "Point",
      coordinates: [-73.856077, 40.848447]
}

有关MongoDB中支持的GeoJSON对象的列表和示例,请参见GeoJSON对象。

MongoDB在一个球体上计算GeoJSON对象的地理空间查询;MongoDB使用WGS84参考系统对GeoJSON对象进行地理空间查询。

遗留的坐标

要计算欧几里德平面上的距离,请将位置数据存储为遗留坐标对并使用2d索引。通过将数据转换为GeoJSON点类型,MongoDB通过2dsphere索引支持对遗留坐标对的球面计算。

要将数据指定为遗留坐标对,可以使用数组(首选)或嵌入式文档。

通过数组指定(首选):

: [ ,  ]

如果指定经纬度坐标,首先列出经度,然后列出纬度;即。

: [,  ]
  • 有效经度值在-180和180之间,两者都包括在内。
  • 有效纬度值在-90和90之间,两者都包括在内。

通过嵌入文档指定:

: { : , :  }

如果指定经纬度坐标,则无论字段名称如何,第一个字段必须包含经度值,第二个字段必须包含纬度值;即。

: { : , :  }

要指定遗留坐标对,首选数组而不是嵌入式文档,因为某些语言不保证关联映射顺序。

空间索引

MongoDB提供了以下地理空间索引类型来支持地理空间查询。

2dsphere

2dsphere索引支持在类地球体上计算几何图形的查询。
要创建一个2dsphere索引,使用db.collection.createIndex()方法并指定字符串文字“2dsphere”作为索引类型:

db.collection.createIndex( {  : "2dsphere" } )

其中,的值是一个GeoJSON对象或一个遗留坐标对。
有关2dsphere索引的更多信息,请参见2dsphere索引。

2d

2d索引支持在二维平面上计算几何图形的查询。虽然该索引可以支持在一个球体上计算的$nearSphere查询,但是如果可能的话,可以对球形查询使用2dsphere索引。

要创建2d索引,使用db.collection.createIndex()方法,指定location字段作为键,字符串文字“2d”作为索引类型:

db.collection.createIndex( {  : "2d" } )

其中,的值是一个遗留坐标对。
有关2d索引的更多信息,请参见2d索引。

地理空间索引和切分集合

在对集合进行分片时,不能使用地理空间索引作为分片键。但是,可以使用不同的字段作为切分键,在切分集合上创建地理空间索引。

分片集合支持以下地理空间操作:

  • $geoNear聚合阶段
  • $near和$near sphere查询操作符(从MongoDB 4.0开始)

从MongoDB 4.0开始,$near和$near sphere查询支持切分集合。

在早期的MongoDB版本中,$near和$near sphere查询不支持切分集合;相反,对于分片集群,必须使用$geoNear聚合阶段或geoNear命令(在MongoDB 4.0和更早的版本中可用)。

您还可以使用$geoWithin和$geoIntersect来查询切分集群的地理空间数据。

覆盖查询

地理空间索引无法覆盖查询。

地理空间查询

提示:

对于球形查询,使用2dsphere索引结果。
对球形查询使用2d索引可能会导致不正确的结果,例如对围绕极点的球形查询使用2d索引。

地理空间查询操作符

MongoDB提供了以下地理空间查询操作:

Name Description
$geoIntersects 选择与GeoJSON几何图形相交的几何图形。2dsphere索引支持$geoIntersects。
$geoWithin 选择包围GeoJSON几何图形中的几何图形。2dsphere和2d索引支持$geoWithin。
$near 返回一个点附近的地理空间对象。需要地理空间索引。2dsphere和2d索引支持$near。
$nearSphere 返回接近球体上某一点的地理空间对象。需要地理空间索引。2dsphere和2d索引支持$nearSphere。

有关详细信息(包括示例),请参见各个参考页面。

地理空间聚合阶段

MongoDB提供了以下地理空间聚集管道阶段:

Stage Description
$geoNear

根据与地理空间点的接近程度返回有序的文档流。为地理空间数据合并了$match、$sort和$limit功能。输出文档包含一个额外的距离字段,并且可以包含一个位置标识符字段。
$geoNear需要一个地理空间索引。

有关更多细节,包括示例,请参见$geoNear参考页面。

地理空间模型

MongoDB地理空间查询可以解释平面或球体上的几何图形。
2dsphere索引只支持球形查询(即在球形表面上解释几何图形的查询)。
2d索引支持平面查询(即在平面上解释几何图形的查询)和一些球形查询。虽然2d索引支持一些球形查询,但是对这些球形查询使用2d索引可能会导致错误。如果可能,对球形查询使用2dsphere索引。

下表列出了地理空间查询操作符,支持查询,每个地理空间操作使用:

Operation Spherical/Flat Query Notes
$near (GeoJSON centroid point in this line and the following line, 2dsphere index) Spherical 还请参阅$nearSphere操作符,它在与GeoJSON和2dsphere索引一起使用时提供了相同的功能。
$near (legacy coordinates, 2d index) Flat  
$nearSphere (GeoJSON point, 2dsphere index) Spherical 提供与使用GeoJSON点和a2dsphere索引的$near操作相同的功能。
对于球形查询,最好使用$nearSphere,它在名称中显式地指定球形查询,而不是$near操作符。
$nearSphere (legacy coordinates, 2d index) Spherical Use GeoJSON points instead.
$geoWithin : { $geometry: … } Spherical  
$geoWithin : { $box: … } Flat  
$geoWithin : { $polygon: … } Flat  
$geoWithin : { $center: … } Flat  
$geoWithin : { $centerSphere: … } Spherical  
$geoIntersects Spherical  
$geoNear aggregation stage (2dsphere index) Spherical  
$geoNear aggregation stage (2d index) Flat  

例子

使用以下文件创建集合地点:

db.places.insert( {
    name: "Central Park",
   location: { type: "Point", coordinates: [ -73.97, 40.77 ] },
   category: "Parks"
} );
db.places.insert( {
   name: "Sara D. Roosevelt Park",
   location: { type: "Point", coordinates: [ -73.9928, 40.7193 ] },
   category: "Parks"
} );
db.places.insert( {
   name: "Polo Grounds",
   location: { type: "Point", coordinates: [ -73.9375, 40.8303 ] },
   category: "Stadiums"
} );

下面的操作在location字段上创建一个2dsphere索引:

db.places.createIndex( { location: "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"
      }
   }
] )

二、查找具有地理空间查询的餐馆

概述

MongoDB的地理空间索引允许您高效地对包含地理空间形状和点的集合执行空间查询。为了展示地理空间特性的功能并比较不同的方法,本教程将指导您编写一个简单的地理空间应用程序的查询过程。

本教程将简要介绍地理空间索引的概念,然后演示它们在$geoWithin、$geoIntersects和$nearSphere中的用法。

假设您正在设计一个移动应用程序来帮助用户查找纽约市的餐馆。应用程序必须:

  • 使用$geoIntersects来确定用户当前的邻域,
  • 使用$geoWithin显示该社区的餐馆数量,以及
  • 使用$nearSphere查找用户指定距离内的餐馆。

本教程将使用一个2dsphere索引来查询关于球面几何的数据。
有关球面和平面几何的更多信息,请参见地理空间模型。

失真

由于将三维球体(如地球)投射到平面上的特性,当在地图上显示时,球面几何将会扭曲。

例如,以经纬度点(0,0)、(80,0)、(80,80)和(0,80)定义的球面平方为例。下图描绘了该区域所覆盖的区域:

MongoDB 地理空间查询_第1张图片

寻找餐馆

前提条件

从https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/neighborhoods.json和https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/restaurants.json下载示例数据集。这些分别包含收集餐馆和社区。

下载数据集后,导入数据库:

mongoimport  -c=restaurants
mongoimport  -c=neighborhoods

一个地理空间索引,并且几乎总是提高$geoWithin和$geoIntersects查询的性能。
因为这些数据是地理上的,所以使用mongo shell在每个集合上创建一个2dsphere索引:

db.restaurants.createIndex({ location: "2dsphere" })
db.neighborhoods.createIndex({ geometry: "2dsphere" })

探索数据

从mongo外壳中查看新创建的餐馆集合中的一个条目:

db.restaurants.findOne()

该查询返回的文档如下:

{
   location: {
      type: "Point",
      coordinates: [-73.856077, 40.848447]
   },
   name: "Morris Park Bake Shop"
}

本餐厅文件对应的位置如下图所示:

MongoDB 地理空间查询_第2张图片

因为本教程使用2dsphere索引,所以location字段中的几何数据必须遵循GeoJSON格式。

现在检查一个条目在邻里收集:

db.neighborhoods.findOne()

该查询将返回如下文档:

{
   geometry: {
      type: "Polygon",
      coordinates: [[
         [ -73.99, 40.75 ],
         ...
         [ -73.98, 40.76 ],
         [ -73.99, 40.75 ]
      ]]
    },
    name: "Hell's Kitchen"
}

该几何图形对应如下图所示的区域:

MongoDB 地理空间查询_第3张图片

找到当前的邻居

假设用户的移动设备可以为用户提供一个合理准确的位置,那么很容易用$geoIntersects找到用户当前的邻居。

假设用户位于-73.93414657经度和40.82302903纬度。为了找到当前的邻域,您将使用特殊的$geometry字段在GeoJSON格式中指定一个点:

db.neighborhoods.findOne({ geometry: { $geoIntersects: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] } } } })

该查询将返回以下结果:

{
    "_id" : ObjectId("55cb9c666c522cafdb053a68"),
    "geometry" : {
        "type" : "Polygon",
        "coordinates" : [
            [
                [
                    -73.93383000695911,
                    40.81949109558767
                ],
                ...
            ]
        ]
    },
    "name" : "Central Harlem North-Polo Grounds"
}

找到附近所有的餐馆

您还可以查询某个给定社区中包含的所有餐馆。在mongo shell中运行以下命令,找到包含该用户的社区,然后计算该社区中的餐馆数量:

var neighborhood = db.neighborhoods.findOne( { geometry: { $geoIntersects: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] } } } } )
db.restaurants.find( { location: { $geoWithin: { $geometry: neighborhood.geometry } } } ).count()

该查询将告诉您,在被请求的社区中有127家餐馆,如下图所示:

MongoDB 地理空间查询_第4张图片

找到附近的餐馆

要查找指定距离内的餐馆,可以使用$geoWithin和$centerSphere以未排序的顺序返回结果,或者使用$maxDistance(如果需要按距离排序结果)来返回结果。

Unsorted with $geoWithin

要在圆形区域内找到餐厅,可以使用$geoWithin和$centerSphere。$centerSphere是一种特定于mongodb的语法,通过指定圆心和半径(以弧度为单位)来表示圆形区域。

$geoWithin不以任何特定的顺序返回文档,因此它可能会首先向用户显示最远的文档。

以下是用户所在5英里范围内的所有餐厅:

db.restaurants.find({ location:
   { $geoWithin:
      { $centerSphere: [ [ -73.93414657, 40.82302903 ], 5 / 3963.2 ] } } })

$centerSphere的第二个参数接受以弧度为单位的半径,因此必须将其除以地球半径(以英里为单位)。有关距离单位之间的转换的更多信息,请参见使用球面几何计算距离。

排序$nearSphere

您还可以使用$nearSphere并指定一个$maxDistance(以米为单位)项。这将返回用户周围5英里内的所有餐馆,按从最近到最远的顺序排序:

var METERS_PER_MILE = 1609.34
db.restaurants.find({ location: { $nearSphere: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] }, $maxDistance: 5 * METERS_PER_MILE } } })

GeoJSON对象

概述
MongoDB支持本页列出的GeoJSON对象类型。
要指定GeoJSON数据,请使用带有以下内容的嵌入式文档:

  • 指定GeoJSON对象类型和的名为type的字段
  • 指定对象坐标的名为coordinates的字段。

如果指定经纬度坐标,首先列出经度,然后是纬度:

  • 有效经度值在-180和180之间,两者都包括在内。
  • 有效纬度值在-90和90之间,两者都包括在内。
: { type:  , coordinates:  }

MongoDB在一个球体上计算GeoJSON对象的地理空间查询;MongoDB使用WGS84参考系统对GeoJSON对象进行地理空间查询。


下面的例子指定了一个GeoJSON点:

{ type: "Point", coordinates: [ 40, 5 ] }

LineString
下面的示例指定了一个GeoJSON LineString:

{ type: "LineString", coordinates: [ [ 40, 5 ], [ 41, 6 ] ] }

多边形
多边形由一组GeoJSON线性坐标数组组成。这些线性环是闭合的线性弦。闭合的线字符串至少有四个坐标对,并指定与第一个和最后一个坐标相同的位置。

连接两个点在曲面上的直线可能包含也可能不包含连接两个点在平面上的同一组坐标。在曲面上连接两个点的直线是测地线。仔细检查点,以避免错误与共享的边缘,以及重叠和其他类型的交叉。

只有一个环的多边形

下面的例子指定了一个GeoJSON多边形,它有一个外部环,没有内部环(或孔)。为了关闭多边形,第一个和最后一个坐标必须匹配:

{
  type: "Polygon",
  coordinates: [ [ [ 0 , 0 ] , [ 3 , 6 ] , [ 6 , 1 ] , [ 0 , 0  ] ] ]
}

对于单环多边形,环不能自交。

有多个环的多边形

对于多环多边形:

  • 第一个描述的环必须是外环。
  • 外环不能自交。
  • 任何内圈都必须完全包含在外圈内。
  • 内环不能相互交叉或重叠。内环不能共用一条边。

下面的例子表示一个带有内环的GeoJSON多边形:

{
  type : "Polygon",
  coordinates : [
     [ [ 0 , 0 ] , [ 3 , 6 ] , [ 6 , 1 ] , [ 0 , 0 ] ],
     [ [ 2 , 2 ] , [ 3 , 3 ] , [ 4 , 2 ] , [ 2 , 2 ] ]
  ]
}

MongoDB 地理空间查询_第5张图片

多点
需要的版本
GeoJSON多点嵌入式文档编码一个点列表。

{
  type: "MultiPoint",
  coordinates: [
     [ -73.9580, 40.8003 ],
     [ -73.9498, 40.7968 ],
     [ -73.9737, 40.7648 ],
     [ -73.9814, 40.7681 ]
  ]
}

MultiLineString
需要的版本
下面的例子指定了一个GeoJSON MultiLineString:

{
  type: "MultiLineString",
  coordinates: [
     [ [ -73.96943, 40.78519 ], [ -73.96082, 40.78095 ] ],
     [ [ -73.96415, 40.79229 ], [ -73.95544, 40.78854 ] ],
     [ [ -73.97162, 40.78205 ], [ -73.96374, 40.77715 ] ],
     [ [ -73.97880, 40.77247 ], [ -73.97036, 40.76811 ] ]
  ]
}

多个多边形
需要的版本
下面的例子指定了一个GeoJSON多多边形:

{
  type: "MultiPolygon",
  coordinates: [
     [ [ [ -73.958, 40.8003 ], [ -73.9498, 40.7968 ], [ -73.9737, 40.7648 ], [ -73.9814, 40.7681 ], [ -73.958, 40.8003 ] ] ],
     [ [ [ -73.958, 40.8003 ], [ -73.9498, 40.7968 ], [ -73.9737, 40.7648 ], [ -73.958, 40.8003 ] ] ]
  ]
}

GeometryCollection
需要的版本
下面的例子存储了GeoJSON类型的GeometryCollection坐标:

{
  type: "GeometryCollection",
  geometries: [
     {
       type: "MultiPoint",
       coordinates: [
          [ -73.9580, 40.8003 ],
          [ -73.9498, 40.7968 ],
          [ -73.9737, 40.7648 ],
          [ -73.9814, 40.7681 ]
       ]
     },
     {
       type: "MultiLineString",
       coordinates: [
          [ [ -73.96943, 40.78519 ], [ -73.96082, 40.78095 ] ],
          [ [ -73.96415, 40.79229 ], [ -73.95544, 40.78854 ] ],
          [ [ -73.97162, 40.78205 ], [ -73.96374, 40.77715 ] ],
          [ [ -73.97880, 40.77247 ], [ -73.97036, 40.76811 ] ]
       ]
     }
  ]
}

 

你可能感兴趣的:(MongoDB,Mongodb,地理空间)