

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 通过 Amazon DocumentDB 查询地理空间数据
<a name="geospatial"></a>

本节将介绍可以怎样使用 Amazon DocumentDB 来查询地理空间数据。阅读本节后，您将能够回答如何在 Amazon DocumentDB 中存储、查询和索引化地理空间数据。

**Topics**
+ [概述](#overview)
+ [索引化和存储地理空间数据](#indexing)
+ [查询地理空间数据](#querying_geospatial)
+ [限制](#limitations)

## 概述
<a name="overview"></a>

地理空间的常见用例涉及来自数据的邻近分析。例如，“查找距离西雅图 50 英里范围内的所有机场”，或“查找距离给定位置最近的餐厅”。Amazon DocumentDB 使用[ GeoJSON 规范](https://datatracker.ietf.org/doc/html/rfc7946)来表示地理空间数据。GeoJSON 是一个对坐标空间中形状进行 JSON 格式化的开源规范。GeoJSON 坐标捕获经度和纬度，表示在类地球球体上的位置。

## 索引化和存储地理空间数据
<a name="indexing"></a>

Amazon DocumentDB 使用“点” GeoJSON 类型来存储地理空间数据。每个 GeoJSON 文档（或子文档）通常由两个字段组成：
+ **类型**：要被表示的形状，它告知 Amazon DocumentDB 如何解释“坐标”字段。目前，Amazon DocumentDB 仅支持点
+ **坐标**：表示为数组中对象的经纬度对：[经度、纬度]

Amazon DocumentDB 还使用 2dsphere 索引来索引化地理空间数据。Amazon DocumentDB 支持索引化点。Amazon DocumentDB 支持用 2dsphere 索引化进行邻近查询。

让我们考虑一个场景，即您正在为送餐服务构建一个应用程序。您希望要在 Amazon DocumentDB 中存储各种餐厅的经纬度对。为此，我们首先建议您对地理空间字段创建一个包含经纬度对的索引。

```
use restaurantsdb 
db.usarestaurants.createIndex({location:"2dsphere"})
```

该命令的输出内容类似如下所示：

```
{
	"createdCollectionAutomatically" : true,
	"numIndexesBefore" : 1,
	"numIndexesAfter" : 2,
	"ok" : 1
}
```

创建索引后，您可以开始将数据插入 Amazon DocumentDB 集合。

```
db.usarestaurants.insert({
   "state":"Washington",
   "city":"Seattle",
   "name":"Thai Palace",
   "rating": 4.8,
   "location":{
      "type":"Point",
      "coordinates":[
         -122.3264,
         47.6009
      ]
   }
});

db.usarestaurants.insert({
   "state":"Washington",
   "city":"Seattle",
   "name":"Noodle House",
   "rating": 4.8,
   "location":{
      "type":"Point",
      "coordinates":[
        -122.3517,
         47.6159
      ]
   }
});

db.usarestaurants.insert({
   "state":"Washington",
   "city":"Seattle",
   "name":"Curry House",
   "rating": 4.8,
   "location":{
      "type":"Point",
      "coordinates":[
         -121.4517,
         47.6229
      ]
   }
});
```

## 查询地理空间数据
<a name="querying_geospatial"></a>

Amazon DocumentDB 支持对地理空间数据的邻近查询、包含查询和交叉点查询。一个良好的邻近查询示例是查找距另一个点（城市）小于某个距离且大于某个距离的所有点（所有机场）。包含查询的一个很好的例子是查找位于指定（纽约州）的所有点 area/polygon （所有机场）。一个良好的交叉点查询示例是查找与某个点（城市）相交的多边形（州）。您可以使用以下地理空间运算符从数据中获取见解。
+ `$nearSphere`：`$nearSphere` 是一个查找运算符，支持查找距 GeoJSON 点最近处到最远处的点。
+ `$geoNear`：`$geoNear` 是一个聚合运算符，支持计算以米为单位的距 GeoJSON 点的距离。
+ `$minDistance`：`$minDistance` 是一个查找运算符，结合 `$nearSphere` 或 `$geoNear` 一起用于筛选距中心点至少指定最小距离的文档。
+ `$maxDistance`：`$maxDistance` 是一个查找运算符，结合 `$nearSphere` 或 `$geoNear` 一起用于筛选距中心点至多指定最大距离的文档。
+ `$geoWithin`：`$geoWithin` 是一个查找运算符，支持查找包含具有以下地理空间数据的文档，这些数据完全存在于指定形状（如多边形）范围内。
+ `$geoIntersects`：`$geoIntersects` 是一个查找运算符，支持查找其地理空间数据与指定 GeoJSON 对象相交的文档。

**注意**  
`$geoNear` 和 `$nearSphere` 要求您在邻近查询中使用的 GeoJSON 字段上有 2dsphere 索引。

### 示例 1
<a name="w2aac47c23c11b9"></a>

在此示例中，您将学习如何查找按照距某地址（点）最近距离排序的所有餐厅（点）。

要执行这样的查询，您可以使用 `$geoNear` 计算一组点距另一点的距离。您也可以添加 `distanceMultiplier` 来测量以千米计的距离。

```
db.usarestaurants.aggregate([
   {
      "$geoNear":{
         "near":{
            "type":"Point",
            "coordinates":[
               -122.3516,
               47.6156
            ]
         },
         "spherical":true,
         "distanceField":"DistanceKilometers",
         "distanceMultiplier":0.001
      }
   }
])
```

上述命令将返回按照距指定点的距离（最近到最远）排序的餐厅。该命令的输出内容类似如下所示 

```
{ "_id" : ObjectId("611f3da985009a81ad38e74b"), "state" : "Washington", "city" : "Seattle", "name" : "Noodle House", "rating" : 4.8, "location" : { "type" : "Point", "coordinates" : [ -122.3517, 47.6159 ] }, "DistanceKilometers" : 0.03422834547294996 }
{ "_id" : ObjectId("611f3da185009a81ad38e74a"), "state" : "Washington", "city" : "Seattle", "name" : "Thai Palace", "rating" : 4.8, "location" : { "type" : "Point", "coordinates" : [ -122.3264, 47.6009 ] }, "DistanceKilometers" : 2.5009390081704277 }
{ "_id" : ObjectId("611f3dae85009a81ad38e74c"), "state" : "Washington", "city" : "Seattle", "name" : "Curry House", "rating" : 4.8, "location" : { "type" : "Point", "coordinates" : [ -121.4517, 47.6229 ] }, "DistanceKilometers" : 67.52845344856914 }
```

要限制查询中的结果数量，可使用 `limit` 或 `num` 选项。

`limit`:

```
db.usarestaurants.aggregate([
   {
      "$geoNear":{
         "near":{
            "type":"Point",
            "coordinates":[
               -122.3516,
               47.6156
            ]
         },
         "spherical":true,
         "distanceField":"DistanceKilometers",
         "distanceMultiplier":0.001,
         "limit": 10
      }
   }
])
```

`num`:

```
db.usarestaurants.aggregate([
   {
      "$geoNear":{
         "near":{
            "type":"Point",
            "coordinates":[
               -122.3516,
               47.6156
            ]
         },
         "spherical":true,
         "distanceField":"DistanceKilometers",
         "distanceMultiplier":0.001,
         "num": 10
      }
   }
])
```

**注意**  
`$geoNear` stage 支持 `limit` 和 `num` 选项来指定要返回的最大文档数。如果未指定 `limit` 或 `num` 选项，则 `$geoNear` 默认最多返回 100 个文档。如果存在 `$limit` stage 的值且此值小于 100，则文档数会被此值覆盖。

### 示例 2
<a name="w2aac47c23c11c11"></a>

在此示例中，您将学习如何查找距特定地址（点）2 千米范围内的所有餐厅（点）。要执行此类查询，您可以在距 GeoJSON 点的最小值 `$minDistance` 和最大值 `$maxDistance` 范围内使用 `$nearSphere`

```
db.usarestaurants.find({
   "location":{
      "$nearSphere":{
         "$geometry":{
            "type":"Point",
            "coordinates":[
               -122.3516,
               47.6156
            ]
         },
         "$minDistance":1,
         "$maxDistance":2000
      }
   }
},
{
   "name":1
})
```

上面的命令将返回距指定点最大距离 2 千米的餐厅。该命令的输出内容类似如下所示 

```
{ "_id" : ObjectId("611f3da985009a81ad38e74b"), "name" : "Noodle House" }
```

## 限制
<a name="limitations"></a>

Amazon DocumentDB 不支持对多边形、、、 LineString MultiPoint MultiPolygon、 MultiLineString和进行查询或索引。 GeometryCollection