这篇文章使用简单的数据集和查询对MongoDB 2.6的地理空间功能进行了快速简单的介绍。
存储地理空间信息
如您所知,您可以存储任何类型的数据,但是如果要查询它们,则需要使用一些坐标,并在它们上创建索引。 MongoDB支持三种用于GeoSpatial查询的索引:
- 2d索引 :使用简单坐标(经度,纬度)。 如文档中所述: 2d索引用于MongoDB 2.2及更早版本中使用的旧坐标对 。 基于这个原因,在这篇文章中我将不做任何详细说明。 仅用于记录2d索引用于查询存储为二维平面上的点的数据
- 2d球形索引 :支持查询类似地球的球形上的任何几何图形,数据可以存储为GeoJSON和传统坐标对(经度,纬度)。 在本文的其余部分,我将使用这种类型的索引,重点介绍GeoJSON。
- Geo Haystack :用于在很小的区域进行查询。 今天它已为应用程序所用,因此在本文中不再赘述。
因此,本文现在将重点介绍具有GeoJSON格式的2d Sphere索引,以存储和查询文档。
那么什么是GeoJSON?
您可以查看http://geojson.org/网站,让我们做一个简短的说明。 GeoJSON是一种用于使用JSON编码各种地理数据结构的格式,并支持以下类型:Point,LineString,Polygon,MultiPoint,MultiLineString,MultiPolygon和Geometry。
对于简单的几何,GeoJSON格式非常简单,基于两个属性:类型和坐标。 让我们举一些例子:
我整个童年时所生活的城市,法国PleneufVal-André,具有以下坐标(摘自Wikipedia)
N°48°35′30.12″,W 2°32′48.84″
该表示法是基于WGS 84 (度,分,秒)系统的纬度和经度的一点。 应用程序/代码不太容易使用,这就是为什么还可以使用以下经度和纬度值来表示完全相同的点的原因:
48.5917,-2.5469
这是使用WGS 84 (十进制)的系统。 这是您在用作开发人员的大多数应用程序/ API中使用的坐标(例如:例如Google Maps / Earth)。
默认情况下,GeoJSON和MongoDB使用这些值,但是坐标必须以经度,纬度顺序存储 ,因此GeoJSON中的这一点应类似于:
- {
- "type": "Point",
- "coordinates": [
- -2.5469,
- 48.5917
- ]
- }
这是一个简单的“要点”,现在让我们来看一条直线,在海滩上散步非常好:
- {
- "type": "LineString",
- "coordinates": [
- [-2.551082,48.5955632],
- [-2.551229,48.594312],
- [-2.551550,48.593312],
- [-2.552400,48.592312],
- [-2.553677, 48.590898]
- ]
- }
因此,使用相同的方法,您将能够创建MultiPoint,MultiLineString,Polygon,MultiPolygon。 也可以使用GeometryCollection将所有这些混合在一个文档中。 以下示例是中央公园上的MultiLineString和Polygon的Geometry集合:
- {
- "type" : "GeometryCollection",
- "geometries" : [
- {
- "type" : "Polygon",
- "coordinates" : [
- [
- [ -73.9580, 40.8003 ],
- [ -73.9498, 40.7968 ],
- [ -73.9737, 40.7648 ],
- [ -73.9814, 40.7681 ],
- [ -73.9580, 40.8003 ]
- ]
- ]
- },
- {
- "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 ] ]
- ]
- }
- ]
- }
注意:如果您想使用http://geojsonlint.com/服务测试/可视化这些JSON文档,则可以。
怎么办? 让我们存储数据!
拥有GeoJSON文档后,您只需将其存储到文档中即可。 例如,如果要存储有关肯尼迪机场的文档及其位置,则可以运行以下命令:
- db.airports.insert(
- {
- "name" : "John F Kennedy Intl",
- "type" : "International",
- "code" : "JFK",
- "loc" : {
- "type" : "Point",
- "coordinates" : [ -73.778889, 40.639722 ]
- }
- }
是的,就是这么简单! 您只需将GeoJSON保存为文档的属性之一(在此示例中为loc)。
查询地理空间信息
现在我们已经将数据存储在MongoDB中,现在可以使用地理空间信息进行一些有趣的查询。
为此,我们需要一个样本数据集。 我使用在不同地方发现的一些开放数据创建了一个。 该数据集包含以下信息:
- 带有美国机场列表的机场集合(点)
- 州列表与美国州列表(MultiPolygon)
我创建这个数据集从不同的来源将opendata( http://geocommons.com/ , http://catalog.data.gov/dataset )和使用toGeoJSON将它们转换成合适的格式。
让我们安装数据集:
- 从这里下载
- 解压缩geo.zip文件
- 使用以下命令mongorestore geo.zip将数据还原到mongoDB实例中
MongoDB允许应用程序对地理空间数据执行以下类型的查询:
- 包含
- 路口
- 接近
显然,除了地理空间运算符之外,您还可以使用所有其他运算符。 现在让我们看一些具体的例子。
包容性
查找加利福尼亚州的所有机场。 为此,您需要获取加利福尼亚位置(多边形),并在查询中使用命令$ geoWithin。 从外壳看起来像:
- use geo
-
- var cal = db.states.findOne( {code : "CA"} );
-
- db.airports.find(
- {
- loc : { $geoWithin : { $geometry : cal.loc } }
- },
- { name : 1 , type : 1, code : 1, _id: 0 }
- );
结果:
- { "name" : "Modesto City - County", "type" : "", "code" : "MOD" }
- ...
- { "name" : "San Francisco Intl", "type" : "International", "code" : "SFO" }
- { "name" : "San Jose International", "type" : "International", "code" : "SJC" }
- ...
因此,查询使用的是“ California MultiPolygon”,并在airports集合中查找以找到这些多边形中的所有机场。 看起来像地图上的下图:
您可以使用任何其他查询功能或条件,例如,可以将查询限制为仅按名称排序的国际机场:
- db.airports.find(
- {
- loc : { $geoWithin : { $geometry : cal.loc } },
- type : "International"
- },
- { name : 1 , type : 1, code : 1, _id: 0 }
- ).sort({ name : 1 });
结果:
- { "name" : "Los Angeles Intl", "type" : "International", "code" : "LAX" }
- { "name" : "Metropolitan Oakland Intl", "type" : "International", "code" : "OAK" }
- { "name" : "Ontario Intl", "type" : "International", "code" : "ONT" }
- { "name" : "San Diego Intl", "type" : "International", "code" : "SAN" }
- { "name" : "San Francisco Intl", "type" : "International", "code" : "SFO" }
- { "name" : "San Jose International", "type" : "International", "code" : "SJC" }
- { "name" : "Southern California International", "type" : "International", "code" : "VCV" }
我不知道您是否已详细查看,但我们正在查询没有索引的这些文档。 您可以使用explain()运行查询以查看发生了什么。 $ geoWithin运算符不需要索引,但是您的查询将更高效,因此我们创建索引:
db.airports.ensureIndex( { "loc" : "2dsphere" } );
运行解释,您会发现差异。
路口
假设您想知道与加利福尼亚州相邻的所有州,为此,我们只需要搜索坐标与加利福尼亚州“相交”的所有州。 这是通过以下查询完成的:
- var cal = db.states.findOne( {code : "CA"} );
- db.states.find(
- {
- loc : { $geoIntersects : { $geometry : cal.loc } } ,
- code : { $ne : "CA" }
- },
- { name : 1, code : 1 , _id : 0 }
- );
结果:
- { "name" : "Oregon", "code" : "OR" }
- { "name" : "Nevada", "code" : "NV" }
- { "name" : "Arizona", "code" : "AZ" }
与之前的$ geoIntersect运算符相同,它不需要索引才能工作,但是使用以下索引会更有效:
db.states.ensureIndex( { loc : "2dsphere" } );
接近
我想在这篇文章中强调的最后一个功能与具有接近性条件的查询有关。 让我们找到距离纽约市中央公园水库不到20公里的所有国际机场。 为此,您将使用$ near运算符。
- db.airports.find(
- {
- loc : {
- $near : {
- $geometry : {
- type : "Point" ,
- coordinates : [-73.965355,40.782865]
- },
- $maxDistance : 20000
- }
- },
- type : "International"
- },
- {
- name : 1,
- code : 1,
- _id : 0
- }
- );
结果:
- { "name" : "La Guardia", "code" : "LGA" }
- { "name" : "Newark Intl", "code" : "EWR"
因此,此查询返回2个机场,最近的是拉瓜迪亚机场,因为$ near运算符按距离对结果进行排序。 同样重要的是在这里提出$ near运算符需要一个索引。
结论
在有关地理空间特征的第一篇文章中,您了解到:
- GeoJSON的基础
- 如何使用包含,相交和接近标准查询文档。
现在,您可以进行更多操作,例如,将其集成到将数据公开到某些UI的应用程序中,或者了解如何将地理空间运算符用于聚合管道。
翻译自: https://www.javacodegeeks.com/2014/09/introduction-to-mongodb-geospatial-feature.html