

# 使用 DynamoDB 中的项目和属性
<a name="WorkingWithItems"></a>

在 Amazon DynamoDB 中，*项目*是属性的集合。每个属性都有各自的名称和值。属性值可以为标量、集或文档类型。有关更多信息，请参阅 [Amazon DynamoDB：工作原理](HowItWorks.md)。

DynamoDB 提供了用于基本的创建、读取、更新和删除 (CRUD) 功能的四项操作。所有这些操作都是原子操作。
+ `PutItem` — 创建项目。
+ `GetItem` — 读取项目。
+ `UpdateItem` — 更新项目。
+ `DeleteItem` — 删除项目。

其中每项操作均需要您指定要处理的项目的主键。例如，要使用 `GetItem` 读取项目，您必须指定该项目的分区键和排序键（如果适用）。

除了四项基本 CRUD 操作之外，DynamoDB 还提供了以下操作：
+ `BatchGetItem` — 从一个或多个表中读取多达 100 个项目。
+ `BatchWriteItem` — 在一个或多个表中创建或删除多达 25 个项目。

这些批处理操作可将多项 CRUD 操作组合成一个请求。此外，批处理操作还可并行读取和写入项目以最大程度地减少响应延迟。

本节将介绍如何使用这些操作并包含了相关主题，例如有条件更新和原子计数器。本节还包括使用 AWS SDK 的示例代码。

**Topics**
+ [DynamoDB 项目大小和格式](CapacityUnitCalculations.md)
+ [读取项目](#WorkingWithItems.ReadingData)
+ [写入项目](#WorkingWithItems.WritingData)
+ [返回值](#WorkingWithItems.ReturnValues)
+ [分批操作](#WorkingWithItems.BatchOperations)
+ [原子计数器](#WorkingWithItems.AtomicCounters)
+ [有条件写入](#WorkingWithItems.ConditionalUpdate)
+ [在 DynamoDB 中使用表达式](Expressions.md)
+ [在 DynamoDB 中使用生存时间（TTL）](TTL.md)
+ [在 DynamoDB 中查询表](Query.md)
+ [在 DynamoDB 中扫描表](Scan.md)
+ [PartiQL – 用于 Amazon DynamoDB 的 SQL 兼容语言](ql-reference.md)
+ [处理项目：Java](JavaDocumentAPIItemCRUD.md)
+ [使用项目：.NET](LowLevelDotNetItemCRUD.md)

# DynamoDB 项目大小和格式
<a name="CapacityUnitCalculations"></a>

DynamoDB 表是无架构的（主键除外），因此，表中的项目可具有不同的属性、大小和数据类型。

项目的总大小是其属性名称和值的长度总和，加上任何适用的开销，如下所述。您可以使用以下准则来估算属性大小：
+ 字符串是使用 UTF-8 二进制编码的 Unicode。字符串大小为 *（属性名 UTF-8 编码的字节数）\$1（UTF-8 编码的字节数）*。
+ 数字的长度是可变的，最多 38 个有效位。系统会删减开头和结尾的 0。数字大小约为 *（属性名 UTF-8 编码的字节数）\$1（每 2 个有效位对应 1 个字节）\$1（1 个字节）*。
+ 必须先采用 base64 格式对二进制值进行编码，然后才能将其发送到 DynamoDB，不过使用值的原始字节长度来计算大小。二进制属性的大小为 *（属性名 UTF-8 编码的字节数）\$1（原始字节数）*。
+ 空属性或布尔属性的大小为 *（属性名 UTF-8 编码的字节数）\$1（1 字节）*。
+ 对于类型为 `List` 或 `Map` 的属性，不论其内容如何，都需要 3 个字节的开销。`List` 或 `Map` 的大小为*（属性名 UTF-8 编码的字节数）\$1 总和（嵌套元素大小）\$1（3 字节）*。空 `List` 或 `Map` 的大小为 *（属性名 UTF-8 编码的字节数）\$1（3 字节）*。
+ 每个 `List` 或 `Map` 元素还需要 1 字节的开销。

**注意**  
建议您选择较短的属性名，而不要选择较长的属性名。这可以帮助您减少所需的存储量，但也可能会降低您使用的 RCU/WCU 量。

出于存储计费目的，每个项目都包括按项目的存储开销，这取决于您启用的功能。
+ DynamoDB 中的所有项目都需要 100 字节的存储开销才能进行索引。
+ 某些 DynamoDB 功能（全局表、事务、使用 DynamoDB 的 Kinesis Data Streams 更改数据捕获）需要额外的存储开销，才能考虑因启用这些功能而产生的系统创建属性。例如，全局表需要额外 48 字节的存储开销。

## 读取项目
<a name="WorkingWithItems.ReadingData"></a>

要从 DynamoDB 表中读取项目，请使用 `GetItem` 操作。必需提供表的名称和所需项目的主键。

**Example**  
以下 AWS CLI 示例将演示如何从 `ProductCatalog` 表读取项目。  

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"1"}}'
```

**注意**  
使用 `GetItem` 时，您必须指定*整个* 主键，而不仅仅是部分主键。例如，如果某个表具有复合主键（分区键和排序键），您必须为分区键和排序键分别提供一个值。

默认情况下，`GetItem` 请求将执行最终一致性读取。您可以改用 `ConsistentRead` 参数来请求强一致性读取。（这会占用额外的读取容量单位，但会返回该项目的最新版本。）

`GetItem` 返回项目的所有属性。您可以使用*投影表达式* 来仅返回一部分属性。有关更多信息，请参阅 [在 DynamoDB 中使用投影表达式](Expressions.ProjectionExpressions.md)。

要返回由 `GetItem` 占用的读取容量单位数，请将 `ReturnConsumedCapacity` 参数设置为 `TOTAL`。

**Example**  
以下 AWS Command Line Interface (AWS CLI) 示例将演示一些可选的 `GetItem` 参数。  

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"1"}}' \
    --consistent-read \
    --projection-expression "Description, Price, RelatedItems" \
    --return-consumed-capacity TOTAL
```

## 写入项目
<a name="WorkingWithItems.WritingData"></a>

要创建、更新或删除 DynamoDB 表中的项目，请使用以下操作之一：
+ `PutItem`
+ `UpdateItem`
+ `DeleteItem`

对于这些操作中的每一项，您必须指定完整的主键，而不仅仅是部分主键。例如，如果某个表具有复合主键（分区键和排序键），您必须为分区键和排序键分别提供一个值。

要返回其中任何操作占用的写入容量单位数，请将 `ReturnConsumedCapacity` 参数设置为以下项之一：
+ `TOTAL` — 返回占用的写入容量单位总数。
+ `INDEXES` — 返回占用的写入容量单位总数，其中包含表的小计和受该操作影响的任何二级索引。
+ `NONE` — 不返回任何写入容量详细信息。（这是默认值。）

### PutItem
<a name="WorkingWithItems.WritingData.PutItem"></a>

`PutItem` 创建新项目。如果表中已存在具有相同键的项目，它将被替换为新项目。

**Example**  
将新项目写入 `Thread` 表。`Thread` 的主键包含 `ForumName`（分区键）和 `Subject`（排序键）。  

```
aws dynamodb put-item \
    --table-name Thread \
    --item file://item.json
```
`--item` 的参数存储在 `item.json` 文件中。  

```
{
    "ForumName": {"S": "Amazon DynamoDB"},
    "Subject": {"S": "New discussion thread"},
    "Message": {"S": "First post in this thread"},
    "LastPostedBy": {"S": "fred@example.com"},
    "LastPostDateTime": {"S": "201603190422"}
}
```

### UpdateItem
<a name="WorkingWithItems.WritingData.UpdateItem"></a>

如果带指定键的项目不存在，则 `UpdateItem` 会创建一个新项目。否则，它会修改现有项目的属性。

您可使用*更新表达式* 指定要修改的属性及其新值。有关更多信息，请参阅 [在 DynamoDB 中使用更新表达式](Expressions.UpdateExpressions.md)。

在更新表达式内，您可使用表达式属性值作为实际值的占位符。有关更多信息，请参阅 [在 DynamoDB 中使用表达式属性值](Expressions.ExpressionAttributeValues.md)。

**Example**  
修改 `Thread` 项目中的各种属性。可选 `ReturnValues` 参数按更新后的情况显示项目。有关更多信息，请参阅 [返回值](#WorkingWithItems.ReturnValues)。  

```
aws dynamodb update-item \
    --table-name Thread \
    --key file://key.json \
    --update-expression "SET Answered = :zero, Replies = :zero, LastPostedBy = :lastpostedby" \
    --expression-attribute-values file://expression-attribute-values.json \
    --return-values ALL_NEW
```

`--key` 的参数存储在 `key.json` 文件中。

```
{
    "ForumName": {"S": "Amazon DynamoDB"},
    "Subject": {"S": "New discussion thread"}
}
```

`--expression-attribute-values` 的参数存储在 `expression-attribute-values.json` 文件中。

```
{
    ":zero": {"N":"0"},
    ":lastpostedby": {"S":"barney@example.com"}
}
```

### DeleteItem
<a name="WorkingWithItems.WritingData.DeleteItem"></a>

`DeleteItem` 删除带指定键的项目。

**Example**  
下面的 AWS CLI 示例说明如何删除 `Thread` 表。  

```
aws dynamodb delete-item \
    --table-name Thread \
    --key file://key.json
```

## 返回值
<a name="WorkingWithItems.ReturnValues"></a>

在某些情况下，您可能希望 DynamoDB 按您修改特定属性值之前或之后的情况返回这些值。`PutItem`、`UpdateItem` 和 `DeleteItem` 操作均具有一个 `ReturnValues` 参数，您可使用该参数返回属性在修改前或修改后的值。

`ReturnValues` 的默认值为 `NONE`，这表示 DynamoDB 不会返回有关已修改属性的任何信息。

下面是 `ReturnValues` 的其他有效设置，这些设置按照 DynamoDB API 操作排列。

### PutItem
<a name="WorkingWithItems.ReturnValues.PutItem"></a>
+ `ReturnValues`: `ALL_OLD`
  + 如果您覆盖了现有项目，`ALL_OLD` 将按覆盖前的情况返回整个项目。
  + 如果您写入了不存在的项目，则 `ALL_OLD` 无效。

### UpdateItem
<a name="WorkingWithItems.ReturnValues.UpdateItem"></a>

`UpdateItem` 的最常见用途是更新现有项目。但是，`UpdateItem` 实际上会执行 *upsert* 操作，这意味着，如果项目尚不存在，upsert 将自动创建项目。
+ `ReturnValues`: `ALL_OLD`
  + 如果您更新了现有项目，`ALL_OLD` 将按更新前的情况返回整个项目。
  + 如果您更新了不存在的项目 (upsert)，则 `ALL_OLD` 无效。
+ `ReturnValues`: `ALL_NEW`
  + 如果您更新了现有项目，`ALL_NEW` 将按更新后的情况返回整个项目。
  + 如果您更新了不存在的项目 (upsert)，`ALL_NEW` 将返回整个项目。
+ `ReturnValues`: `UPDATED_OLD`
  + 如果您更新了现有项目，`UPDATED_OLD` 将仅返回已更新的属性（按更新前的情况）。
  + 如果您更新了不存在的项目 (upsert)，则 `UPDATED_OLD` 无效。
+ `ReturnValues`: `UPDATED_NEW`
  + 如果您更新了现有项目，`UPDATED_NEW` 将仅返回受影响的属性（按更新后的情况）。
  + 如果您更新了不存在的项目（upsert），`UPDATED_NEW` 将仅返回已更新的属性（按更新后的情况）。

### DeleteItem
<a name="WorkingWithItems.ReturnValues.DeleteItem"></a>
+ `ReturnValues`: `ALL_OLD`
  + 如果您删除了现有项目，`ALL_OLD` 将按删除前情况返回整个项目。
  + 如果您删除了不存在的项目，`ALL_OLD` 不会返回任何数据。

## 分批操作
<a name="WorkingWithItems.BatchOperations"></a>

对于需要读取和写入多个项目的应用程序，DynamoDB 提供了 `BatchGetItem` 和 `BatchWriteItem` 操作。使用这些操作可减少从您的应用程序到 DynamoDB 的网络往返行程数。此外，DynamoDB 还可并行执行各个读取或写入操作。您的应用程序将受益于这种并行机制，并且无需管理并发度或线程。

批处理操作本质上是围绕多个读取或写入请求的包装程序。例如，如果一个 `BatchGetItem` 请求包含五个项目，则 DynamoDB 会代表您执行五次 `GetItem` 操作。同样，如果一个 `BatchWriteItem` 请求包含两个放置请求和四个删除请求，则 DynamoDB 会执行两次 `PutItem` 和四次 `DeleteItem` 请求。

通常，除非一个批处理操作中的*所有* 请求都失败，否则批处理操作不会失败。例如，假设您执行了一个 `BatchGetItem` 操作，但该批处理中的单独的 `GetItem` 请求之一失败。在这种情况下，`BatchGetItem` 会返回来自失败的 `GetItem` 请求的键和数据。该批处理中的其他 `GetItem` 请求不会受影响。

### BatchGetItem
<a name="WorkingWithItems.BatchOperations.BatchGetItem"></a>

一个 `BatchGetItem` 操作可包含多达 100 个单独的 `GetItem` 请求且可检索多达 16 MB 的数据。此外，一个 `BatchGetItem` 操作可从多个表中检索项目。

**Example**  
从 `Thread` 表中检索两个项目，并使用投影表达式仅返回一部分属性。  

```
aws dynamodb batch-get-item \
    --request-items file://request-items.json
```
`--request-items` 的参数存储在 `request-items.json` 文件中。  

```
{
    "Thread": {
        "Keys": [
            {
                "ForumName":{"S": "Amazon DynamoDB"},
                "Subject":{"S": "DynamoDB Thread 1"}
            },
            {
                "ForumName":{"S": "Amazon S3"},
                "Subject":{"S": "S3 Thread 1"}
            }
        ],
        "ProjectionExpression":"ForumName, Subject, LastPostedDateTime, Replies"
    }
}
```

### BatchWriteItem
<a name="WorkingWithItems.BatchOperations.BatchWriteItem"></a>

`BatchWriteItem` 操作可包含多达 25 个单独的 `PutItem` 和 `DeleteItem` 请求且最多可写入 16 MB 的数据。（单个项目的最大大小为 400 KB。） 此外，一个 `BatchWriteItem` 操作可在多个表中放置或删除项目。

**注意**  
`BatchWriteItem` 不支持 `UpdateItem` 请求。

**Example**  
它向 `ProductCatalog` 表中写入两个项目。  

```
aws dynamodb batch-write-item \
    --request-items file://request-items.json
```
`--request-items` 的参数存储在 `request-items.json` 文件中。  

```
{
    "ProductCatalog": [
        {
            "PutRequest": {
                "Item": {
                    "Id": { "N": "601" },
                    "Description": { "S": "Snowboard" },
                    "QuantityOnHand": { "N": "5" },
                    "Price": { "N": "100" }
                }
            }
        },
        {
            "PutRequest": {
                "Item": {
                    "Id": { "N": "602" },
                    "Description": { "S": "Snow shovel" }
                }
            }
        }
    ]
}
```

## 原子计数器
<a name="WorkingWithItems.AtomicCounters"></a>

您可以使用 `UpdateItem` 操作来实施*原子计数器*，一种无条件递增的数字属性，不会干扰其他写入请求。（所有写入请求的应用顺序跟接收顺序相同。） 使用原子计数器时，更新不是幂等的。换言之，该数值在您每次调用 `UpdateItem` 时递增或者递减。如果用于更新原子计数器的增量值为正，则可能导致计数偏多。如果该增量值为负，则可能导致计数偏少。

您可使用原子计数器跟踪网站的访问者的数量。在这种情况下，您的应用程序将以某个数字值递增，无论其当前值如何。如果 `UpdateItem` 操作失败，该应用程序只需重试该操作即可。这会产生更新两次计数器的风险，但您可能能够容忍对网站访问者的计数稍微偏多或偏少。

在无法容忍计数偏多或偏少的情况下（例如，在银行应用程序中），原子计数器将不适用。在此情况下，使用有条件更新比使用原子计数器更安全。

有关更多信息，请参阅 [对数值属性进行加减](Expressions.UpdateExpressions.md#Expressions.UpdateExpressions.SET.IncrementAndDecrement)。

**Example**  
以下 AWS CLI 示例以 5 为递增量提高产品的 `Price`。在本示例中，更新计数器之前，已知该项目存在。（由于 `UpdateItem` 不是幂等的，`Price` 在您每次运行此代码时增加。）   

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id": { "N": "601" }}' \
    --update-expression "SET Price = Price + :incr" \
    --expression-attribute-values '{":incr":{"N":"5"}}' \
    --return-values UPDATED_NEW
```

## 有条件写入
<a name="WorkingWithItems.ConditionalUpdate"></a>

默认情况下，DynamoDB 写入操作（`PutItem`、`DeleteItem`）是*无条件的*：每项操作都会覆盖带指定主键的现有项目。

DynamoDB 可以选择性地对这些操作支持有条件写入。有条件写入仅在项目属性满足一个或多个预期条件时才会成功。否则，它会返回错误。

条件写入会根据项目的最新更新版本检查其条件。请注意，如果该项目以前不存在，或者最近对该项目成功执行的操作是删除，则条件写入将找不到以前的项目。

 有条件写入在很多情况下很有用。例如，您可能希望 `PutItem` 操作仅在尚不存在具有相同主键的项目时成功。或者，如果某个项目的其中一个属性具有一个特定值，您可以阻止 `UpdateItem` 操作修改该项目。

有条件写入在多个用户尝试修改同一项目的情况下很有用。请考虑下图，其中两位用户（Alice 和 Bob）正在处理 DynamoDB 表中的同一项目。

![\[用户 Alice 和 Bob 尝试修改 ID 为 1 的项目，这表明需要有条件写入。\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/images/update-no-condition.png)


假设 Alice 使用 AWS CLI 将 `Price` 属性更新为 8。

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"1"}}' \
    --update-expression "SET Price = :newval" \
    --expression-attribute-values file://expression-attribute-values.json
```

`--expression-attribute-values` 的参数存储在文件 `expression-attribute-values.json` 中：

```
{
    ":newval":{"N":"8"}
}
```

现在假设 Bob 稍后发出一个相似的 `UpdateItem` 请求，但将 `Price` 更改为 12。对于 Bob，`--expression-attribute-values` 参数类似于以下形式。

```
{
    ":newval":{"N":"12"}
}
```

Bob 的请求成功，但 Alice 之前的更新丢失了。

要请求有条件 `PutItem`、`DeleteItem` 或 `UpdateItem`，请指定一个条件表达式。*条件表达式* 是一个包含属性名称、条件运算符和内置函数的字符串。整个表达式的求值结果必须为 true。否则，该操作将失败。

现在考虑下图，该图展示了有条件写入将如何阻止 Alice 的更新被覆盖。

![\[阻止用户 Bob 的更新覆盖用户 Alice 对同一项目的更改的有条件写入。\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/images/update-yes-condition.png)


Alice 首次尝试将 `Price` 更新为 8，但仅在当前 `Price` 为 10 时才执行此操作。

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"1"}}' \
    --update-expression "SET Price = :newval" \
    --condition-expression "Price = :currval" \
    --expression-attribute-values file://expression-attribute-values.json
```

`--expression-attribute-values` 的参数存储在 `expression-attribute-values.json` 文件中。

```
{
    ":newval":{"N":"8"},
    ":currval":{"N":"10"}
}
```

由于条件的计算结果为 true，Alice 的更新成功了。

接下来，Bob 尝试将 `Price` 更新为 12，但仅在当前 `Price` 为 10 时才执行此操作。对于 Bob，`--expression-attribute-values` 参数类似于以下形式。

```
{
    ":newval":{"N":"12"},
    ":currval":{"N":"10"}
}
```

由于 Alice 之前已将 `Price` 更改为 8，因此条件表达式的计算结果为 false，Bob 的更新失败。

有关更多信息，请参阅 [DynamoDB 条件表达式 CLI 示例](Expressions.ConditionExpressions.md)。

### 带条件写入幂等性
<a name="WorkingWithItems.ConditionalWrites.Idempotence"></a>

如果条件检查位于同一个要更新的属性上，则条件写入可以是*幂等* 的。这意味着，仅当项目中的某些属性值与您在请求时期望它们具有的值匹配时，DynamoDB 才执行给定的写入请求。

例如，假设您发出一个 `UpdateItem` 请求来以 3 为递增量提高某个项目的 `Price`，但仅在 `Price` 当前为 20 时才执行此操作。在已发送该请求但尚未获得返回的结果之间的时间内，网络出现了错误，您不知道该请求是否成功。由于此条件写入是幂等的，您可以重试同一 `UpdateItem` 请求，而 DynamoDB 将仅在 `Price` 当前为 20 时更新项目。

### 带条件写入占用的容量单位
<a name="WorkingWithItems.ConditionalWrites.ReturnConsumedCapacity"></a>

即使 `ConditionExpression` 在条件写入过程中计算结果为 false，DynamoDB 仍消耗表的写入容量。消耗量取决于现有项目的大小（或最少为 1 个）。例如，如果现有项目为 300kb，而您尝试创建或更新的新项目为 310kb，则当条件失败时，消耗的写入容量单位将为 300，当条件成功时，消耗的写入容量单位将为 310。如果这是新项目（没有现有项目），当条件失败时，消耗的写入容量单位将为 1；当条件成功时，则消耗的写入容量单位为 310。

**注意**  
写入操作仅占用*写入*容量单位。它们从不占用*读取*容量单位。

失败的条件写入将返回 `ConditionalCheckFailedException`。发生这种情况时，您不会在响应中收到有关所消耗写入容量的任何信息。

要返回有条件写入过程中占用的写入容量单位的数量，请使用 `ReturnConsumedCapacity` 参数：
+ `TOTAL` — 返回占用的写入容量单位总数。
+ `INDEXES` — 返回占用的写入容量单位总数，其中包含表的小计和受该操作影响的任何二级索引。
+ `NONE` — 不返回任何写入容量详细信息。（这是默认值。）

  

**注意**  
与全局二级索引不同的是，本地二级索引与其表共享其预调配的吞吐容量。对本地二级索引执行的读取和写入活动会占用表的预置的吞吐容量。

# 在 DynamoDB 中使用表达式
<a name="Expressions"></a>

在 Amazon DynamoDB 中，您可以使用*表达式*来指定要从项目中读取哪些属性，在满足条件时写入数据，指定如何更新项目、定义查询和筛选查询结果。

该表描述了基本表达式语法和可用的表达式种类。


| 表达式类型 | 说明 | 
| --- | --- | 
| 投影表达式 | 当您使用 GetItem、Query 或 Scan 等操作时，投影表达式可标识要从项目中检索的属性。 | 
| 条件表达式 | 条件表达式确定在您使用 PutItem、UpdateItem 和 DeleteItem 操作时应修改哪些项目。 | 
| 更新表达式 | 更新表达式指定 UpdateItem 将如何修改项目的属性，例如，设置标量值或者删除列表或映射中的元素。 | 
| 键条件表达式 | 键条件表达式确定查询将从表或索引中读取哪些项目。 | 
| 筛选表达式 | 筛选表达式可确定查询结果中应返回给您的项目。所有其他结果将会丢弃。 | 

请参阅下面几节，了解有关表达式语法的信息以及有关每种表达式类型的详细信息。

**Topics**
+ [在 DynamoDB 中使用表达式时引用项目属性](Expressions.Attributes.md)
+ [DynamoDB 中的表达式属性名称（别名）](Expressions.ExpressionAttributeNames.md)
+ [在 DynamoDB 中使用表达式属性值](Expressions.ExpressionAttributeValues.md)
+ [在 DynamoDB 中使用投影表达式](Expressions.ProjectionExpressions.md)
+ [在 DynamoDB 中使用更新表达式](Expressions.UpdateExpressions.md)
+ [DynamoDB 中的条件表达式和筛选表达式、运算符及函数](Expressions.OperatorsAndFunctions.md)
+ [DynamoDB 条件表达式 CLI 示例](Expressions.ConditionExpressions.md)

**注意**  
为了向后兼容性，DynamoDB 还支持不使用表达式的条件参数。有关更多信息，请参阅 [遗留 DynamoDB 条件参数](LegacyConditionalParameters.md)。  
新应用程序应使用表达式而不是旧式参数。

# 在 DynamoDB 中使用表达式时引用项目属性
<a name="Expressions.Attributes"></a>

本节介绍如何在 Amazon DynamoDB 中的表达式中引用项目属性。您可以使用任何属性，即使它深层嵌套在多个列表和映射中。

**Topics**
+ [顶级属性](#Expressions.Attributes.TopLevelAttributes)
+ [嵌套属性](#Expressions.Attributes.NestedAttributes)
+ [文档路径](#Expressions.Attributes.NestedElements.DocumentPathExamples)

**项目示例：ProductCatalog**  
本页上的示例使用 `ProductCatalog` 表中的以下项目示例。（此表在 [在 DynamoDB 中使用的示例表和数据](AppendixSampleTables.md) 中说明。）

```
{
    "Id": 123,
    "Title": "Bicycle 123",
    "Description": "123 description",
    "BicycleType": "Hybrid",
    "Brand": "Brand-Company C",
    "Price": 500,
    "Color": ["Red", "Black"],
    "ProductCategory": "Bicycle",
    "InStock": true,
    "QuantityOnHand": null,
    "RelatedItems": [
        341,
        472,
        649
    ],
    "Pictures": {
        "FrontView": "http://example.com/products/123_front.jpg",
        "RearView": "http://example.com/products/123_rear.jpg",
        "SideView": "http://example.com/products/123_left_side.jpg"
    },
    "ProductReviews": {
	    "FiveStar": [
	    		"Excellent! Can't recommend it highly enough! Buy it!",
	    		"Do yourself a favor and buy this."
	    ],
	    "OneStar": [
	    		"Terrible product! Do not buy this."
	    ]
    },
    "Comment": "This product sells out quickly during the summer",
    "Safety.Warning": "Always wear a helmet"
 }
```

请注意以下几点：
+ 分区键值 (`Id`) 是 `123`。没有排序键。
+ 大多数属性都具有标量数据类型，例如 `String`、`Number`、`Boolean` 和 `Null`。
+ 一个属性 (`Color`）是一个 `String Set`。
+ 以下属性是文档数据类型：
  + `RelatedItems` 列表。每个元素都是相关产品的 `Id`。
  + `Pictures` 的映射。每个元素都是图片的简短描述，以及相应图片文件的 URL。
  + `ProductReviews` 的映射。每个元素代表一个评级和一个与该评级相对应的评论列表。最初，此映射填充五星级和一星级评论。

## 顶级属性
<a name="Expressions.Attributes.TopLevelAttributes"></a>

如果属性没有嵌入其他属性，则视为*顶级*。对于 `ProductCatalog` 项目，顶级属性如下所示：
+ `Id`
+ `Title`
+ `Description`
+ `BicycleType`
+ `Brand`
+ `Price`
+ `Color`
+ `ProductCategory`
+ `InStock`
+ `QuantityOnHand`
+ `RelatedItems`
+ `Pictures`
+ `ProductReviews`
+ `Comment`
+ `Safety.Warning`

所有这些顶级属性都是标量，除了 `Color`（列表）、`RelatedItems`（列表）、`Pictures`（映射）和 `ProductReviews`（映射）。

## 嵌套属性
<a name="Expressions.Attributes.NestedAttributes"></a>

如果属性嵌入其他属性，则视为*嵌套*。要访问嵌套属性，请使用*取消引用运算符*：
+ `[n]`— 用于列表元素
+ `.`（点）-用于映射元素

### 访问列表元素
<a name="Expressions.Attributes.NestedElements.AccessingListElements"></a>

列表元素的取消引用运算符是 **[*n*]**，其中，*n* 是元素编号。列表元素从 0 开始，因此 [0] 表示列表中的第一个元素，[1] 表示第二个元素，依此类推。下面是一些示例：
+ `MyList[0]`
+ `AnotherList[12]`
+ `ThisList[5][11]`

元素 `ThisList[5]` 本身就是一个嵌套列表。因此，`ThisList[5][11]` 指的是该列表中的第 12 个元素。

方括号内的数字必须为非负整数。因此，以下表达式是无效的：
+ `MyList[-1]`
+ `MyList[0.4]`

### 访问映射元素
<a name="Expressions.Attributes.NestedElements.AccessingMapElements"></a>

地图元素的取消引用运算符为 **.**（一个点）。使用点作为映射中元素之间的分隔符：
+ `MyMap.nestedField`
+ `MyMap.nestedField.deeplyNestedField`

## 文档路径
<a name="Expressions.Attributes.NestedElements.DocumentPathExamples"></a>

在表达式中，您可以使用*文档路径*来告诉 DynamoDB 在哪里可以找到属性。对于顶级属性，文档路径只是属性名称。对于嵌套属性，您可以使用取消引用运算符构建文档路径。

下面是文档路径的一些示例。（请参阅 [在 DynamoDB 中使用表达式时引用项目属性](#Expressions.Attributes)。）
+ 顶级标量属性。

   `Description`
+ 顶级列表属性。（这将返回整个列表，而不仅仅是一些元素。）

  `RelatedItems`
+ 第三个元素来自 `RelatedItems` 列表。（请记住，列表元素是从零开始的。）

  `RelatedItems[2]`
+ 产品的正视图。

  `Pictures.FrontView`
+ 所有五星评论。

  `ProductReviews.FiveStar`
+ 第一个五星级评论。

  `ProductReviews.FiveStar[0]`

**注意**  
文档路径的最大深度为 32。因此，路径中取消引用运算符的数量不能超过此限制。

您可以在文档路径中使用任何属性名称，只要它们符合以下要求：
+ 第一个字符是 `a-z`、`A-Z` 或 `0-9`
+ 第二个字符（如果存在）是 `a-z` 或 `A-Z`

**注意**  
如果属性名称不满足此要求，则您必须将表达式属性名称定义为占位符。

有关更多信息，请参阅 [DynamoDB 中的表达式属性名称（别名）](Expressions.ExpressionAttributeNames.md)。

# DynamoDB 中的表达式属性名称（别名）
<a name="Expressions.ExpressionAttributeNames"></a>

*表达式属性名称*是您在 Amazon DynamoDB 表达式中使用的别名（或占位符），用作实际属性名称的替换项。表达式属性名称必须以井号（`#`）开头，后跟一个或多个字母数字字符。还允许使用下划线（`_`）字符。

本节介绍您必须使用表达式属性名称的几种情况。

**注意**  
本节中的示例使用 AWS Command Line Interface (AWS CLI)。

**Topics**
+ [保留字](#Expressions.ExpressionAttributeNames.ReservedWords)
+ [包含特殊字符的属性名称](#Expressions.ExpressionAttributeNames.AttributeNamesContainingSpecialCharacters)
+ [嵌套属性](#Expressions.ExpressionAttributeNames.NestedAttributes)
+ [重复引用属性名称](#Expressions.ExpressionAttributeNames.RepeatingAttributeNames)

## 保留字
<a name="Expressions.ExpressionAttributeNames.ReservedWords"></a>

有时，您可能需要写入的表达式包含与 DynamoDB 保留字冲突的属性名。（有关保留关键字的完整列表，请参阅 [DynamoDB 中的保留字](ReservedWords.md)。）

例如，以下 AWS CLI 示例将由于 `COMMENT` 是保留字而失败。

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "Comment"
```

要解决此问题，您可使用诸如 `Comment` 的表达式属性名称来替换 `#c`。`#`（井号）是必需的，指示这是属性名称的占位符。AWS CLI 示例现在如下所示。

```
aws dynamodb get-item \
     --table-name ProductCatalog \
     --key '{"Id":{"N":"123"}}' \
     --projection-expression "#c" \
     --expression-attribute-names '{"#c":"Comment"}'
```

**注意**  
如果属性名称以数字开头、包含空格或包含保留字，则您*必须* 在表达式中使用表达式属性名称替换该属性的名称。

## 包含特殊字符的属性名称
<a name="Expressions.ExpressionAttributeNames.AttributeNamesContainingSpecialCharacters"></a>

在表达式中，点（“.”）将解释为文档路径中的分隔符字符。然而，DynamoDB 还允许您在属性名称中使用点字符和其他特殊字符，例如连字符（“-”）。在一些情况下这会造成混淆。为了说明这种情况，假设您要从 `Safety.Warning` 项目中检索 `ProductCatalog` 属性（请参阅 [在 DynamoDB 中使用表达式时引用项目属性](Expressions.Attributes.md)）。

假设您希望使用投影表达式访问 `Safety.Warning`。

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "Safety.Warning"
```

DynamoDB 将返回空结果，而不是预期字符串 ("`Always wear a helmet`")。这是因为，DynamoDB 将表达式中的一个点解释为文档路径分隔符。在这种情况下，您必须定义表达式属性名称（例如 `#sw`）来替换 `Safety.Warning`。然后，您可以使用以下投影表达式。

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "#sw" \
    --expression-attribute-names '{"#sw":"Safety.Warning"}'
```

接下来 DynamoDB 将返回正确结果。

**注意**  
如果属性名称包含圆点（“.”）或连字符（“-”），则*必须* 使用表达式属性名称替换表达式中该属性的名称。

## 嵌套属性
<a name="Expressions.ExpressionAttributeNames.NestedAttributes"></a>

假设您想访问嵌套属性 `ProductReviews.OneStar`。在表达式属性名称中，DynamoDB 将点（“.”）视为属性名称中的字符。要引用嵌套属性，请为文档路径中的每个元素定义一个表达式属性名称：
+ `#pr — ProductReviews`
+ `#1star — OneStar`

然后，您可以对投影表达式使用 `#pr.#1star`。

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "#pr.#1star"  \
    --expression-attribute-names '{"#pr":"ProductReviews", "#1star":"OneStar"}'
```

接下来 DynamoDB 将返回正确结果。

## 重复引用属性名称
<a name="Expressions.ExpressionAttributeNames.RepeatingAttributeNames"></a>

表达式属性名称在需要重复引用相同属性名称时很有帮助。例如，请考虑以下用于从 `ProductCatalog` 项目中检索一些评论的表达式。

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "ProductReviews.FiveStar, ProductReviews.ThreeStar, ProductReviews.OneStar"
```

要使表达式更加简洁，您可以使用诸如 `ProductReviews` 的表达式属性名称来替换 `#pr`。现在，修订的表达式如下所示。
+  `#pr.FiveStar, #pr.ThreeStar, #pr.OneStar` 

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "#pr.FiveStar, #pr.ThreeStar, #pr.OneStar" \
    --expression-attribute-names '{"#pr":"ProductReviews"}'
```

如果您定义表达式属性名称，则该名称在整个表达式中的使用方式必须一致。另外，您不能忽略 `#` 符号。

# 在 DynamoDB 中使用表达式属性值
<a name="Expressions.ExpressionAttributeValues"></a>

Amazon DynamoDB 中的*表达式属性值*可充当变量。它们是您想要比较的实际值的替代项，您可能直到运行时才知道这些值。表达式属性值必须以冒号 (`:`) 开头，后跟一个或多个字母数字字符。

例如，假设您希望返回提供 `Black` 且成本`500` 或更少的所有 `ProductCatalog` 项目。您可以使用 `Scan` 操作与过滤器表达式相同，如此 AWS Command Line Interface(AWS CLI） 示例。

```
aws dynamodb scan \
    --table-name ProductCatalog \
    --filter-expression "contains(Color, :c) and Price <= :p" \
    --expression-attribute-values file://values.json
```

`--expression-attribute-values` 的参数存储在 `values.json` 文件中。

```
{
    ":c": { "S": "Black" },
    ":p": { "N": "500" }
}
```

如果您定义表达式属性值，则该值在整个表达式中的使用方式必须一致。另外，您不能忽略 `:` 符号。

表达式属性值与关键条件表达式、条件表达式、更新表达式和筛选表达式一起使用。

# 在 DynamoDB 中使用投影表达式
<a name="Expressions.ProjectionExpressions"></a>

要从表中读取数据，您可以使用 `GetItem`、`Query`，或者 `Scan`。默认情况下，Amazon DynamoDB 会返回所有项目属性。要仅获取部分属性而不是全部属性，请使用投影表达式。

*投影表达式*是用于标识所需属性的字符串。要检索单个属性，请指定其名称。对于多个属性，名称必须以逗号分隔。

下面是一些投影表达式的示例，基于 `ProductCatalog` 商品来自 [在 DynamoDB 中使用表达式时引用项目属性](Expressions.Attributes.md)：
+ 单个顶级属性。

  `Title `
+ 三个顶级属性。DynamoDB 检索整个 `Color` 设置。

  `Title, Price, Color`
+ 4 个顶级属性。DynamoDB 将返回 `RelatedItems` 和 `ProductReviews`。

  `Title, Description, RelatedItems, ProductReviews`

**注意**  
投影表达式对预调配吞吐量消耗没有影响。DynamoDB 将依据项目大小确定消耗的容量，而不是依据返回到应用程序的数据量。

**保留字和特殊字符**

DynamoDB 具有保留字和特殊字符。DynamoDB 允许您使用这些保留字和特殊字符作为名称，但建议您不要这样做，因为在表达式中使用这些名称时必须使用其别名。有关完整列表，请参阅[DynamoDB 中的保留字](ReservedWords.md)。

在以下情况下，您需要使用表达式属性名称代替实际名称：
+ 属性名称位于 DynamoDB 中的保留字列表中。
+ 属性名称不符合第一个字符是 `a-z` 或 `A-Z`，第二个字符（如果存在）是 `a-Z`、`A-Z` 或 `0-9` 的要求。
+ 属性名称包含 **\$1**（哈希）或 **:**（冒号）。

以下 AWS CLI 示例介绍了如何将投影表达式与 `GetItem` 运算一起使用。此投影表达式检索顶级标量属性 (`Description`)，列表中的第一个元素 (`RelatedItems[0]`) 和嵌套在地图中的列表 (`ProductReviews.FiveStar`)。

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '"Id": { "N": "123" } \
    --projection-expression "Description, RelatedItems[0], ProductReviews.FiveStar"
```

对于此示例，将返回以下 JSON。

```
{
    "Item": {
        "Description": {
            "S": "123 description"
        },
        "ProductReviews": {
            "M": {
                "FiveStar": {
                    "L": [
                        {
                            "S": "Excellent! Can't recommend it highly enough! Buy it!"
                        },
                        {
                            "S": "Do yourself a favor and buy this."
                        }
                    ]
                }
            }
        },
        "RelatedItems": {
            "L": [
                {
                    "N": "341"
                }
            ]
        }
    }
}
```

# 在 DynamoDB 中使用更新表达式
<a name="Expressions.UpdateExpressions"></a>

`UpdateItem` 操作会更新现有项目，或者将新项目添加到表中（如果该新项目尚不存在）。您必须提供要更新的项目的键。您还必须提供更新表达式，指示您要修改的属性以及要分配给这些属性的值。

*更新表达式* 指定 `UpdateItem` 将如何修改项目的属性，例如，设置标量值或者删除列表或映射中的元素。

下面是更新表达式的语法摘要。

```
update-expression ::=
    [ SET action [, action] ... ]
    [ REMOVE action [, action] ...]
    [ ADD action [, action] ... ]
    [ DELETE action [, action] ...]
```

更新表达式包含一个或多个子句。每个子句以 `SET`、`REMOVE`、`ADD` 或 `DELETE` 关键字开头。您可在更新表达式中按任意顺序包含其中任意子句。但是，每个操作关键字只能出现一次。

每个子句中存在一个或多个操作，用逗号分隔。每个操作表示一个数据修改。

此部分中的示例基于`ProductCatalog`中所示的 [在 DynamoDB 中使用投影表达式](Expressions.ProjectionExpressions.md) 项目。

以下主题介绍了 `SET` 操作的一些不同使用案例。

**Topics**
+ [SET – 修改或添加项目属性](#Expressions.UpdateExpressions.SET)
+ [REMOVE – 从项目中删除属性](#Expressions.UpdateExpressions.REMOVE)
+ [ADD – 更新数值和集](#Expressions.UpdateExpressions.ADD)
+ [DELETE – 从集中删除元素](#Expressions.UpdateExpressions.DELETE)
+ [使用多个更新表达式](#Expressions.UpdateExpressions.Multiple)

## SET – 修改或添加项目属性
<a name="Expressions.UpdateExpressions.SET"></a>

在更新表达式中使用 `SET` 操作可将一个或多个属性添加到项目。如果任意这些属性已存在，则将由新值覆盖。如果您要避免覆盖现有属性，则可以将 `SET` 与 `if_not_exists` 函数结合使用。`if_not_exists` 函数特定于 `SET` 操作，只能在更新表达式中使用。

当您使用 `SET` 更新列表元素时，将使用您指定的新数据替代该元素的内容。如果元素尚不存在，`SET` 会将新元素附加到列表的末尾。

如果在单个 `SET` 操作中添加多个元素，则元素会按照元素编号的顺序排序。

您还可使用 `SET` 来加或减 `Number` 类型的属性。要执行多个 `SET` 操作，请使用逗号分隔它们。

在以下语法摘要中：
+ *path* 元素是项目的文档路径。
+ **operand** 元素可以为项目的文档路径，或者为函数。

```
set-action ::=
    path = value

value ::=
    operand
    | operand '+' operand
    | operand '-' operand

operand ::=
    path | function

function ::=
    if_not_exists (path, value)
```

如果项目在指定路径中不包含属性，则 `if_not_exists` 的求值结果为 `value`。否则，它的求值结果为 `path`。

以下 `PutItem` 操作创建将在示例中引用的示例项目。

```
aws dynamodb put-item \
    --table-name ProductCatalog \
    --item file://item.json
```

`--item` 的参数存储在 `item.json` 文件中。（为简单起见，仅使用了几个项目属性。）

```
{
    "Id": {"N": "789"},
    "ProductCategory": {"S": "Home Improvement"},
    "Price": {"N": "52"},
    "InStock": {"BOOL": true},
    "Brand": {"S": "Acme"}
}
```

**Topics**
+ [修改属性](#Expressions.UpdateExpressions.SET.ModifyingAttributes)
+ [添加列表和映射](#Expressions.UpdateExpressions.SET.AddingListsAndMaps)
+ [将元素添加到列表](#Expressions.UpdateExpressions.SET.AddingListElements)
+ [添加嵌套映射属性](#Expressions.UpdateExpressions.SET.AddingNestedMapAttributes)
+ [对数值属性进行加减](#Expressions.UpdateExpressions.SET.IncrementAndDecrement)
+ [将元素附加到列表](#Expressions.UpdateExpressions.SET.UpdatingListElements)
+ [防止覆盖现有属性](#Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites)

### 修改属性
<a name="Expressions.UpdateExpressions.SET.ModifyingAttributes"></a>

**Example**  
更新 `ProductCategory` 和 `Price` 属性。  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET ProductCategory = :c, Price = :p" \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
`--expression-attribute-values` 的参数存储在 `values.json` 文件中。  

```
{
    ":c": { "S": "Hardware" },
    ":p": { "N": "60" }
}
```

**注意**  
在 `UpdateItem` 操作中，`--return-values ALL_NEW` 将导致 DynamoDB 按更新后的情况返回项目。

### 添加列表和映射
<a name="Expressions.UpdateExpressions.SET.AddingListsAndMaps"></a>

**Example**  
添加新列表和新映射。  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET RelatedItems = :ri, ProductReviews = :pr" \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
`--expression-attribute-values` 的参数存储在 `values.json` 文件中。  

```
{
    ":ri": {
        "L": [
            { "S": "Hammer" }
        ]
    },
    ":pr": {
        "M": {
            "FiveStar": {
                "L": [
                    { "S": "Best product ever!" }
                ]
            }
        }
    }
}
```

### 将元素添加到列表
<a name="Expressions.UpdateExpressions.SET.AddingListElements"></a>

**Example**  
将新元素添加到 `RelatedItems` 列表。（请记住，列表元素从 0 开始，因此 [0] 表示列表中的第一个元素，[1] 表示第二个元素，依此类推。）  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET RelatedItems[1] = :ri" \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
`--expression-attribute-values` 的参数存储在 `values.json` 文件中。  

```
{
    ":ri": { "S": "Nails" }
}
```

**注意**  
当您使用 `SET` 更新列表元素时，将使用您指定的新数据替代该元素的内容。如果元素尚不存在，`SET` 会将新元素附加到列表的末尾。  
如果在单个 `SET` 操作中添加多个元素，则元素会按照元素编号的顺序排序。

### 添加嵌套映射属性
<a name="Expressions.UpdateExpressions.SET.AddingNestedMapAttributes"></a>

**Example**  
添加一些嵌套映射属性。  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET #pr.#5star[1] = :r5, #pr.#3star = :r3" \
    --expression-attribute-names file://names.json \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
`--expression-attribute-names` 的参数存储在 `names.json` 文件中。  

```
{
    "#pr": "ProductReviews",
    "#5star": "FiveStar",
    "#3star": "ThreeStar"
}
```
`--expression-attribute-values` 的参数存储在 `values.json` 文件中。  

```
{
    ":r5": { "S": "Very happy with my purchase" },
    ":r3": {
        "L": [
            { "S": "Just OK - not that great" }
        ]
    }
}
```

**重要**  
如果父映射不存在，则无法更新嵌套映射属性。如果您在父映射 (`ProductReviews`) 不存在时尝试更新嵌套属性（例如 `ProductReviews.FiveStar`），则 DynamoDB 会返回 `ValidationException`，并显示消息*“The document path provided in the update expression is invalid for update.”*  
在创建稍后将更新嵌套映射属性的项目时，请初始化父属性的空映射。例如：  

```
{
    "Id": {"N": "789"},
    "ProductReviews": {"M": {}},
    "Metadata": {"M": {}}
}
```
这使您可以像 `ProductReviews.FiveStar` 一样更新嵌套属性，而不会出现错误。

### 对数值属性进行加减
<a name="Expressions.UpdateExpressions.SET.IncrementAndDecrement"></a>

您可以对现有数值属性执行加减运算。为此，请使用 `+`（加号）和 `-`（减号）运算符。

**Example**  
降低项目的 `Price`。  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET Price = Price - :p" \
    --expression-attribute-values '{":p": {"N":"15"}}' \
    --return-values ALL_NEW
```
要提高 `Price`，请在更新表达式中使用 `+` 运算符。

### 将元素附加到列表
<a name="Expressions.UpdateExpressions.SET.UpdatingListElements"></a>

您可将元素添加到列表的末尾。为此，请将 `SET` 与 `list_append` 函数结合使用。（函数名区分大小写。） `list_append` 函数特定于 `SET` 操作，只能在更新表达式中使用。语法如下所示。
+ `list_append (list1, list2)`

该函数将选取两个列表作为输入，并将所有元素从 `list2` 附加到 ` list1`。

**Example**  
在[将元素添加到列表](#Expressions.UpdateExpressions.SET.AddingListElements)中，您创建 `RelatedItems` 列表并填充两个元素：`Hammer` 和 `Nails`。现在您将另外两个元素附加到 `RelatedItems` 的末尾。  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET #ri = list_append(#ri, :vals)" \
    --expression-attribute-names '{"#ri": "RelatedItems"}' \
    --expression-attribute-values file://values.json  \
    --return-values ALL_NEW
```
`--expression-attribute-values` 的参数存储在 `values.json` 文件中。  

```
{
    ":vals": {
        "L": [
            { "S": "Screwdriver" },
            {"S": "Hacksaw" }
        ]
    }
}
```
最后，您将另外一个元素添加到 `RelatedItems` 的 *beginning*。为此，请交换 `list_append` 元素的顺序。（请记住，`list_append` 将选取两个列表作为输入，并会将第二个列表附加到第一个列表。）  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET #ri = list_append(:vals, #ri)" \
    --expression-attribute-names '{"#ri": "RelatedItems"}' \
    --expression-attribute-values '{":vals": {"L": [ { "S": "Chisel" }]}}' \
    --return-values ALL_NEW
```
生成的 `RelatedItems` 属性现在包含 5 个元素，其顺序如下：`Chisel`、`Hammer`、`Nails`、`Screwdriver`、`Hacksaw`。

### 防止覆盖现有属性
<a name="Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites"></a>

**Example**  
设置项目的 `Price`，但仅当项目还没有 `Price` 属性时设置。（如果 `Price` 已存在，则不执行任何操作。）  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET Price = if_not_exists(Price, :p)" \
    --expression-attribute-values '{":p": {"N": "100"}}' \
    --return-values ALL_NEW
```

## REMOVE – 从项目中删除属性
<a name="Expressions.UpdateExpressions.REMOVE"></a>

在更新表达式中使用 `REMOVE` 操作可在 Amazon DynamoDB 中从某个项目删除一个或多个元素。要执行多个 `REMOVE` 操作，请使用逗号分隔它们。

下面是更新表达式中的 `REMOVE` 的语法摘要。唯一的操作数是您要删除的属性的文档路径。

```
remove-action ::=
    path
```

**Example**  
从项目中删除部分属性。（如果属性不存在，则不会执行任何操作。）  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "REMOVE Brand, InStock, QuantityOnHand" \
    --return-values ALL_NEW
```

### 从列表中删除元素
<a name="Expressions.UpdateExpressions.REMOVE.RemovingListElements"></a>

您可使用 `REMOVE` 从列表中删除各个元素。

**Example**  
在[将元素附加到列表](#Expressions.UpdateExpressions.SET.UpdatingListElements)中，您修改了列表属性 (`RelatedItems`)，使它包含 5 个元素：  
+ `[0]`—`Chisel`
+ `[1]`—`Hammer`
+ `[2]`—`Nails`
+ `[3]`—`Screwdriver`
+ `[4]`—`Hacksaw`
以下 AWS Command Line Interface (AWS CLI) 示例从列表中删除 `Hammer` 和 `Nails`。  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "REMOVE RelatedItems[1], RelatedItems[2]" \
    --return-values ALL_NEW
```
删除 `Hammer` 和 `Nails` 之后，剩下的元素将会移位。此列表现在包含以下元素：  
+ `[0]`—`Chisel`
+ `[1]`—`Screwdriver`
+ `[2]`—`Hacksaw`

## ADD – 更新数值和集
<a name="Expressions.UpdateExpressions.ADD"></a>

**注意**  
通常，我们建议使用 `SET` 而不是 `ADD` 来确保幂等运算。

在更新表达式中使用 `ADD` 操作可将新属性及其值添加到项目。

如果属性已存在，则 `ADD` 的行为取决于属性的数据类型：
+ 如果属性是数字，并且添加的值也是数字，则该值将按数学运算与现有属性相加。（如果该值为负数，则从现有属性减去该值。）
+ 如果属性是集合，并且您添加的值也是集合，则该值将附加到现有集合中。

**注意**  
`ADD` 操作仅支持数字和集合数据类型。

要执行多个 `ADD` 操作，请使用逗号分隔它们。

在以下语法摘要中：
+ *path* 元素是属性的文档路径。属性必须为 `Number` 或 set 数据类型。
+ *value* 元素是要与属性相加的值（对于 `Number` 数据类型），或者是要附加到属性中的集合（对于 set 类型）。

```
add-action ::=
    path value
```

以下主题介绍了 `ADD` 操作的一些不同使用案例。

**Topics**
+ [添加数值](#Expressions.UpdateExpressions.ADD.Number)
+ [将元素添加到集](#Expressions.UpdateExpressions.ADD.Set)

### 添加数值
<a name="Expressions.UpdateExpressions.ADD.Number"></a>

假设 `QuantityOnHand` 属性不存在。以下 AWS CLI 示例会将 `QuantityOnHand` 设置为 5。

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "ADD QuantityOnHand :q" \
    --expression-attribute-values '{":q": {"N": "5"}}' \
    --return-values ALL_NEW
```

既然 `QuantityOnHand` 存在，您可重新运行该示例以使 `QuantityOnHand` 每次增加 5。

### 将元素添加到集
<a name="Expressions.UpdateExpressions.ADD.Set"></a>

假设 `Color` 属性不存在。以下 AWS CLI 示例会将 `Color` 设置为包含两个元素的字符串集。

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "ADD Color :c" \
    --expression-attribute-values '{":c": {"SS":["Orange", "Purple"]}}' \
    --return-values ALL_NEW
```

既然 `Color` 存在，您可向其添加更多元素。

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "ADD Color :c" \
    --expression-attribute-values '{":c": {"SS":["Yellow", "Green", "Blue"]}}' \
    --return-values ALL_NEW
```

## DELETE – 从集中删除元素
<a name="Expressions.UpdateExpressions.DELETE"></a>

**重要**  
`DELETE` 操作仅支持 `Set` 数据类型。

在更新表达式中使用 `DELETE` 操作可从集合中删除一个或多个元素。要执行多个 `DELETE` 操作，请使用逗号分隔它们。

在以下语法摘要中：
+ *path* 元素是属性的文档路径。该属性必须是集数据类型。
+ *子网* 是您要从 *path* 中删除的一个或多个元素。您必须指定 *subset* 作为集类型。

```
delete-action ::=
    path subset
```

**Example**  
在[将元素添加到集](#Expressions.UpdateExpressions.ADD.Set)中，您创建 `Color` 字符串集合。本示例将从该集合中删除部分元素。  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "DELETE Color :p" \
    --expression-attribute-values '{":p": {"SS": ["Yellow", "Purple"]}}' \
    --return-values ALL_NEW
```

## 使用多个更新表达式
<a name="Expressions.UpdateExpressions.Multiple"></a>

您可以在单个更新表达式中使用多个操作。在应用任何操作之前，将根据项目的状态对所有属性引用进行解析。

**Example**  
给定项目 `{"id": "1", "a": 1, "b": 2, "c": 3}` 时，以下表达式删除 `a` 并交换 `b` 及 `c` 的值：  

```
aws dynamodb update-item \
    --table-name test \
    --key '{"id":{"S":"1"}}' \
    --update-expression "REMOVE a SET b = a, c = b" \
    --return-values ALL_NEW
```
结果是 `{"id": "1", "b": 1, "c": 2}`。尽管在同一个表达式中 `a` 被移除并向 `b` 重新赋值，但两个引用都将解析为其原始值。

**Example**  
如果要修改属性的值并彻底删除另一个属性，可以在单个语句中使用 SET 和 REMOVE 操作。此操作会将 `Price` 值降至 15，同时还会从项目中删除 `InStock` 属性。  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET Price = Price - :p REMOVE InStock" \
    --expression-attribute-values '{":p": {"N":"15"}}' \
    --return-values ALL_NEW
```

**Example**  
如果您想在添加到列表的同时更改另一个属性的值，则可以在单个语句中使用两个 SET 操作。此操作会将 “Nails” 添加到 `RelatedItems` 列表属性中，并将 `Price` 值设置为 21。  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET RelatedItems[1] = :newValue, Price = :newPrice" \
    --expression-attribute-values '{":newValue": {"S":"Nails"}, ":newPrice": {"N":"21"}}'  \
    --return-values ALL_NEW
```

# DynamoDB 中的条件表达式和筛选表达式、运算符及函数
<a name="Expressions.OperatorsAndFunctions"></a>

要操作 DynamoDB 表中的数据，请使用 `PutItem`、`UpdateItem` 和 `DeleteItem` 操作。对于这些数据处理操作，您可指定条件表达式 来确定应修改的项目。如果条件表达式的计算结果为 true，则操作成功。否则，该操作将失败。

本节介绍用于在 Amazon DynamoDB 中编写筛选表达式和条件表达式的内置函数和关键字。有关 DynamoDB 的函数和编程的更多详细信息，请参阅[使用 DynamoDB 和 AWS SDK 编程](Programming.md)和 [DynamoDB API 参考](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/)。

**Topics**
+ [筛选条件和条件表达式的语法](#Expressions.OperatorsAndFunctions.Syntax)
+ [进行比较](#Expressions.OperatorsAndFunctions.Comparators)
+ [函数](#Expressions.OperatorsAndFunctions.Functions)
+ [逻辑评估](#Expressions.OperatorsAndFunctions.LogicalEvaluations)
+ [圆括号](#Expressions.OperatorsAndFunctions.Parentheses)
+ [条件的优先顺序](#Expressions.OperatorsAndFunctions.Precedence)

## 筛选条件和条件表达式的语法
<a name="Expressions.OperatorsAndFunctions.Syntax"></a>

在以下语法摘要中，*操作数* 可以为下列对象：
+ 顶级属性名称，例如 `Id`、`Title`、`Description` 或 `ProductCategory`
+ 引用嵌套属性的文档路径

```
condition-expression ::=
      operand comparator operand
    | operand BETWEEN operand AND operand
    | operand IN ( operand (',' operand (, ...) ))
    | function
    | condition AND condition
    | condition OR condition
    | NOT condition
    | ( condition )

comparator ::=
    =
    | <>
    | <
    | <=
    | >
    | >=

function ::=
    attribute_exists (path)
    | attribute_not_exists (path)
    | attribute_type (path, type)
    | begins_with (path, substr)
    | contains (path, operand)
    | size (path)
```

## 进行比较
<a name="Expressions.OperatorsAndFunctions.Comparators"></a>

使用以下比较器将操作数与单个值进行比较：
+ `a = b` – 如果 *a* 等于 *b*，则为 True。
+ `a <> b` – 如果 *a* 不等于 *b*，则为 True。
+ `a < b` – 如果 *a* 小于 *b*，则为 True。
+ `a <= b` – 如果 *a* 小于等于 *b*，则为 True。
+ `a > b` – 如果 *a* 大于 *b*，则为 True。
+ `a >= b` – 如果 *a* 大于等于 *b*，则为 True。

使用 `BETWEEN` 和 `IN` 关键字来将操作数与值范围或值的枚举值列表进行比较：
+ `a BETWEEN b AND c` – 如果 *a* 大于或等于 *b*，且小于或等于 *c*，则为 True。
+ `a IN (b, c, d) ` – 如果 *a* 等于列表中的任何值 — 例如 *b*、*c* 或 *d*，则为 True。列表最多可以包含 100 个值，以逗号分隔。

## 函数
<a name="Expressions.OperatorsAndFunctions.Functions"></a>

使用以下函数确定项目中是否存在某个属性，或者对属性求值。这些函数名称区分大小写。对于嵌套属性，您必须提供其完整文档路径。


****  

| 函数 | 说明 | 
| --- | --- | 
|  `attribute_exists (path)`  | 如果项目包含 `path` 指定的属性，则为 true。 示例：检查 `Product` 表中的项目是否具有侧视图图片。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  | 
|  `attribute_not_exists (path)`  | 如果项目中不存在由 `path` 指定的属性，则为 true。 示例：检查项目是否具有 `Manufacturer` 属性。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  | 
|  `attribute_type (path, type)`  |  如果指定路径中的属性为特定数据类型，则为 true。`type` 参数必须是下列类型之一： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) 您必须使用 `type` 参数的表达式属性值。 示例：检查 `QuantityOnHand` 属性是否为列表类型。在本示例中，`:v_sub` 为字符串 `L` 的占位符。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) 您必须使用 `type` 参数的表达式属性值。  | 
|  `begins_with (path, substr)`  |  如果 `path` 指定的属性以特定子字符串开头，则为 true。 示例：检查前视图图片 URL 的前几个字符是否为 `http://`。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) 表达式属性值 `:v_sub` 是 `http://` 的占位符。  | 
|  `contains (path, operand)`  | 如果 `path` 指定的属性为以下之一，则为 true： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) 如果由 `path` 指定的属性为 `String`，则 `operand` 必须为 `String`。如果指定的属性 `path` 是一个 `Set`，`operand` 必须是集合的元素类型。 路径和操作数必须不同。也就是说，`contains (a, a)` 返回错误。 示例：检查 `Brand` 属性是否包含子字符串 `Company`。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) 表达式属性值 `:v_sub` 是 `Company` 的占位符。 示例：检查产品是否有红色。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) 表达式属性值 `:v_sub` 是 `Red` 的占位符。 | 
|  `size (path)`  | 返回一个代表属性大小的数字。以下是与 `size` 结合使用的有效数据类型。  如果属性类型为 `String`，则 `size` 将返回字符串的长度。 示例：检查字符串 `Brand` 是否少于等于 20 个字符。表达式属性值 `:v_sub` 是 `20` 的占位符。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  如果属性类型为 `Binary`，则 `size` 将返回属性值中的字节数。 示例：假设 `ProductCatalog` 项目有一个名为 `VideoClip` 的二进制属性，该属性包含使用中的产品的简短视频。以下表达式将检查 `VideoClip` 是否超过 64000 个字节。表达式属性值 `:v_sub` 是 `64000` 的占位符。[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  如果属性是一个 `Set` 数据类型，则 `size` 将返回集合中的元素数。 示例：检查产品是否有多种颜色。表达式属性值 `:v_sub` 是 `1` 的占位符。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  如果属性类型为 `List` 或 `Map`，则 `size` 将返回子元素数。 示例：检查 `OneStar` 评论的数量是否超过了特定阈值。表达式属性值 `:v_sub` 是 `3` 的占位符。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  | 

## 逻辑评估
<a name="Expressions.OperatorsAndFunctions.LogicalEvaluations"></a>

使用 `AND`、`OR` 和 `NOT` 关键字执行逻辑评估。在以下列表中，*a* 和 *b* 代表要评估的条件。
+ `a AND b` – 如果 *a* 和 *b* 均为 true，则为 True。
+ `a OR b` – 如果 *a* 和/或 *b* 为 true，则为 True。
+ `NOT a` – 如果 *a* 为 false，则为 True。如果 *a* 为 true，则为 False。

以下是操作中 AND 的代码示例。

`dynamodb-local (*)> select * from exprtest where a > 3 and a < 5;`

## 圆括号
<a name="Expressions.OperatorsAndFunctions.Parentheses"></a>

使用圆括号更改逻辑评估的优先顺序。例如，假设条件 *a* 和 *b* 为 true，而条件 *c* 为 false。以下表达式的计算结果为 True：
+ `a OR b AND c`

但是，如果将一个条件括在圆括号中，则会先对该条件求值。例如，以下表达式的计算结算为 False：
+  `(a OR b) AND c`

**注意**  
您可以在表达式中嵌套圆括号。最里面的部分最先评估。

以下是逻辑评估中带有括号的代码示例。

`dynamodb-local (*)> select * from exprtest where attribute_type(b, string) or ( a = 5 and c = “coffee”);`

## 条件的优先顺序
<a name="Expressions.OperatorsAndFunctions.Precedence"></a>

 DynamoDB 使用以下优先顺序规则从左向右评估条件：
+ `= <> < <= > >=`
+ `IN`
+ `BETWEEN`
+ `attribute_exists attribute_not_exists begins_with contains`
+ 圆括号
+ `NOT`
+ `AND`
+ `OR`

# DynamoDB 条件表达式 CLI 示例
<a name="Expressions.ConditionExpressions"></a>

下面是使用条件表达式的一些 AWS Command Line Interface (AWS CLI) 示例。这些示例基于`ProductCatalog`中介绍的 [在 DynamoDB 中使用表达式时引用项目属性](Expressions.Attributes.md) 表。此表的分区键是 `Id`；没有排序键。以下 `PutItem` 操作创建示例所引用的 `ProductCatalog` 项目例子。

```
aws dynamodb put-item \
    --table-name ProductCatalog \
    --item file://item.json
```

`--item` 的参数存储在 `item.json` 文件中。（为简单起见，仅使用了几个项目属性。）

```
{
    "Id": {"N": "456" },
    "ProductCategory": {"S": "Sporting Goods" },
    "Price": {"N": "650" }
}
```

**Topics**
+ [带条件放置](#Expressions.ConditionExpressions.PreventingOverwrites)
+ [带条件删除](#Expressions.ConditionExpressions.AdvancedComparisons)
+ [带条件更新](#Expressions.ConditionExpressions.SimpleComparisons)
+ [条件表达式示例](#Expressions.ConditionExpressions.ConditionalExamples)

## 带条件放置
<a name="Expressions.ConditionExpressions.PreventingOverwrites"></a>

`PutItem` 操作覆盖具有相同主键的项目（如果存在）。如果要避免这种情况，请使用条件表达式。这样，只有当相关的项目还没有相同的主键时，才能继续写入。

以下示例使用 `attribute_not_exists()` 在尝试写入操作之前检查表中是否存在主键。

**注意**  
如果主键同时包含分区键（pk）和排序键（sk），该参数将在尝试写入操作之前检查 `attribute_not_exists(pk)` 和 `attribute_not_exists(sk)` 作为整个语句的计算结果是 true 还是 false。

```
aws dynamodb put-item \
    --table-name ProductCatalog \
    --item file://item.json \
    --condition-expression "attribute_not_exists(Id)"
```

如果条件表达式的计算结果为 false，DynamoDB 将返回以下错误消息：有条件请求失败。

**注意**  
有关 `attribute_not_exists` 和其他函数的更多信息，请参阅 [DynamoDB 中的条件表达式和筛选表达式、运算符及函数](Expressions.OperatorsAndFunctions.md)。

## 带条件删除
<a name="Expressions.ConditionExpressions.AdvancedComparisons"></a>

要执行有条件删除，请将 `DeleteItem` 操作与条件表达式一起使用。要继续执行操作，条件表达式的求值结果必须为 true；否则操作将失败。

考虑上面定义的项目。

假设您要删除该项目，但只能在以下条件下删除：
+  `ProductCategory` 为“Sporting Goods”或“Gardening Supplies”。
+  `Price` 介于 500 和 600 之间。

以下示例尝试删除该项目。

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"456"}}' \
    --condition-expression "(ProductCategory IN (:cat1, :cat2)) and (Price between :lo and :hi)" \
    --expression-attribute-values file://values.json
```

`--expression-attribute-values` 的参数存储在 `values.json` 文件中。

```
{
    ":cat1": {"S": "Sporting Goods"},
    ":cat2": {"S": "Gardening Supplies"},
    ":lo": {"N": "500"},
    ":hi": {"N": "600"}
}
```

**注意**  
在条件表达式中，`:`（冒号字符）表示*表达式属性值*-实际值的占位符。有关更多信息，请参阅 [在 DynamoDB 中使用表达式属性值](Expressions.ExpressionAttributeValues.md)。  
有关 `IN`、`AND` 和其他关键字的更多信息，请参阅[DynamoDB 中的条件表达式和筛选表达式、运算符及函数](Expressions.OperatorsAndFunctions.md)。

在本示例中，`ProductCategory` 比较的计算结果为 true，但 `Price` 比较的计算结果为 false。这导致条件表达式的计算结果为 false，并且 `DeleteItem` 操作失败。

## 带条件更新
<a name="Expressions.ConditionExpressions.SimpleComparisons"></a>

要执行有条件更新，请将 `UpdateItem` 操作与条件表达式一起使用。要继续执行操作，条件表达式的求值结果必须为 true；否则操作将失败。

**注意**  
`UpdateItem` 还支持*更新表达式*，您在其中指定要对项目进行的修改。有关更多信息，请参阅 [在 DynamoDB 中使用更新表达式](Expressions.UpdateExpressions.md)。

假定您从上面定义的项目开始。

以下示例执行 `UpdateItem` 操作。它试图将产品的 `Price` 减少 75，但是如果当前 `Price` 小于或等于 500，条件表达式会阻止更新。

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --update-expression "SET Price = Price - :discount" \
    --condition-expression "Price > :limit" \
    --expression-attribute-values file://values.json
```

`--expression-attribute-values` 的参数存储在 `values.json` 文件中。

```
{
    ":discount": { "N": "75"},
    ":limit": {"N": "500"}
}
```

如果起始 `Price` 为 650，则 `UpdateItem` 操作会将 `Price` 降至 575。如果您再次运行 `UpdateItem` 操作，`Price` 将降至 500。如果您第三次运行该操作，则条件表达式的计算结果为 false，并且更新失败。

**注意**  
在条件表达式中，`:`（冒号字符）表示*表达式属性值*-实际值的占位符。有关更多信息，请参阅 [在 DynamoDB 中使用表达式属性值](Expressions.ExpressionAttributeValues.md)。  
有关“*>*”和其他运算符的更多信息，请参阅 [DynamoDB 中的条件表达式和筛选表达式、运算符及函数](Expressions.OperatorsAndFunctions.md)。

## 条件表达式示例
<a name="Expressions.ConditionExpressions.ConditionalExamples"></a>

有关以下示例中使用的函数的更多信息，请参阅 [DynamoDB 中的条件表达式和筛选表达式、运算符及函数](Expressions.OperatorsAndFunctions.md)。若要详细了解如何在表达式中指定不同的属性类型，请参阅 [在 DynamoDB 中使用表达式时引用项目属性](Expressions.Attributes.md)。

### 检查项目中的属性
<a name="Expressions.ConditionExpressions.CheckingForAttributes"></a>

您可以检查任何属性是否存在。如果条件表达式的计算结果为 true，则操作成功；否则操作失败。

以下示例使用了 `attribute_not_exists`，以便仅当产品没有 `Price` 属性时才删除产品。

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "attribute_not_exists(Price)"
```

DynamoDB 还提供了一个 `attribute_exists` 函数。以下示例仅当收到不好的评价时删除产品。

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "attribute_exists(ProductReviews.OneStar)"
```

### 检查属性类型
<a name="Expressions.ConditionExpressions.CheckingForAttributeType"></a>

您可以使用 `attribute_type` 函数检查属性值的数据类型。如果条件表达式的计算结果为 true，则操作成功；否则操作失败。

以下示例使用 `attribute_type` 删除具有类型为“字符串集”的 `Color` 属性的产品。

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "attribute_type(Color, :v_sub)" \
    --expression-attribute-values file://expression-attribute-values.json
```

`--expression-attribute-values` 的参数存储在 expression-attribute-values.json 文件中。

```
{
    ":v_sub":{"S":"SS"}
}
```

### 检查字符串的起始值
<a name="Expressions.ConditionExpressions.CheckingBeginsWith"></a>

您可以使用 `begins_with` 函数检查字符串属性值是否以特定子字符串开头。如果条件表达式的计算结果为 true，则操作成功；否则操作失败。

以下示例使用 `begins_with` 删除 `FrontView` 映射的 `Pictures` 元素以特定值开头的产品。

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "begins_with(Pictures.FrontView, :v_sub)" \
    --expression-attribute-values file://expression-attribute-values.json
```

`--expression-attribute-values` 的参数存储在 expression-attribute-values.json 文件中。

```
{
    ":v_sub":{"S":"http://"}
}
```

### 检查集中的元素
<a name="Expressions.ConditionExpressions.CheckingForContains"></a>

您可以使用 `contains` 函数检查集中的元素或在字符串内查找子字符串。如果条件表达式的计算结果为 true，则操作成功；否则操作失败。

以下示例使用 `contains` 删除 `Color` 字符串集中包含具有特定值的元素的产品。

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "contains(Color, :v_sub)" \
    --expression-attribute-values file://expression-attribute-values.json
```

`--expression-attribute-values` 的参数存储在 expression-attribute-values.json 文件中。

```
{
    ":v_sub":{"S":"Red"}
}
```

### 检查属性值的大小
<a name="Expressions.ConditionExpressions.CheckingForSize"></a>

您可以使用 `size` 函数检查属性值的大小。如果条件表达式的计算结果为 true，则操作成功；否则操作失败。

以下示例使用 `size` 删除 `VideoClip` 二进制属性的大小超过 `64000` 字节的产品。

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "size(VideoClip) > :v_sub" \
    --expression-attribute-values file://expression-attribute-values.json
```

`--expression-attribute-values` 的参数存储在 expression-attribute-values.json 文件中。

```
{
    ":v_sub":{"N":"64000"}
}
```

# 在 DynamoDB 中使用生存时间（TTL）
<a name="TTL"></a>

DynamoDB 的生存时间（TTL）是一种经济实惠的方法，用于删除不再相关的项目。通过 TTL，您可以定义每个项目的过期时间戳，指示何时不再需要某个项目。DynamoDB 会在项目过期时间到期后的几天内自动将其删除，而不会消耗写入吞吐量。

要使用 TTL，请先在表上启用它，然后定义一个特定的属性来存储 TTL 过期时间戳。时间戳必须以[数字](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes)数据类型存储，采用 [Unix 纪元时间格式](https://en.wikipedia.org/wiki/Unix_time)，精确到秒级粒度。如果项目具有非数字类型的 TTL 属性，TTL 流程会忽略该项目。每次创建或更新项目时，您都可以计算过期时间并将其保存在 TTL 属性中。

系统可以随时删除具有有效、已过期 TTL 属性的项目，通常是在过期后的几天内。您仍然可以更新待删除的过期项目，包括更改或删除其 TTL 属性。更新过期项目时，我们建议您使用条件表达式来确保该项目随后未被删除。使用筛选表达式从[扫描](Scan.md#Scan.FilterExpression)和[查询](Query.FilterExpression.md)结果中删除过期的项目。

已删除项目的工作原理与通过典型删除操作删除的项目类似。删除后，项目会以服务删除而不是用户删除的形式进入 DynamoDB Streams，并像其它删除操作一样从本地二级索引和全局二级索引中删除。

如果使用全局表的[全局表版本 2019.11.21（当前版）](GlobalTables.md)，并且还使用生存时间特征，则 DynamoDB 会将 TTL 删除复制到所有副本表。在出现 TTL 到期的区域中，初始 TTL 删除不会消耗写入容量单位（WCU）。但是，在每个副本区域中，当使用预置的容量时，复制到副本表的 TTL 删除将消耗一个复制的写入容量单位，或在使用按需容量模式时消耗一个复制的写入容量单位，并且将收取适用的费用。

有关 TTL 的更多信息，请参阅以下主题：

**Topics**
+ [在 DynamoDB 中启用生存时间（TTL）](time-to-live-ttl-how-to.md)
+ [在 DynamoDB 中计算生存时间（TTL）](time-to-live-ttl-before-you-start.md)
+ [使用过期项目和生存时间（TTL）](ttl-expired-items.md)

# 在 DynamoDB 中启用生存时间（TTL）
<a name="time-to-live-ttl-how-to"></a>

**注意**  
为了协助调试 TTL 功能和验证该功能是否正常运行，为项目 TTL 提供的值将以纯文本形式记录在 DynamoDB 诊断日志中。

您可以在 Amazon DynamoDB 控制台中，在 AWS Command Line Interface（AWS CLI）中，或者对于任何支持的 AWS SDK 使用 [Amazon DynamoDB API 参考](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/)，来启用 TTL。在所有分区中启用 TTL 大约需要一个小时。

## 使用 AWS 控制台启用 DynamoDB TTL
<a name="time-to-live-ttl-how-to-enable-console"></a>

1. 登录 AWS 管理控制台，打开 DynamoDB 控制台：[https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)。

1. 选择**表**，然后选择您要修改的表。

1. 在**其它设置**选项卡的**生存时间(TTL)** 部分中，选择**开启**来启用 TTL。

1. 在表上启用 TTL 时，DynamoDB 要求您标识此服务在确定项目是否符合过期条件时将查找的特定属性名称。如下所示的 TTL 属性名称区分大小写，并且必须与读取和写入操作中定义的属性相匹配。不匹配将导致已过期的项目被取消删除。重命名 TTL 属性需要您禁用 TTL，然后使用新属性重新启用它。禁用后，TTL 将在大约 30 分钟内继续处理删除。必须对已恢复的表重新配置 TTL。  
![\[区分大小写的 TTL 属性名称，DynamoDB 使用该属性来确定项目是否符合过期条件。\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/images/EnableTTL-Settings.png)

1. （可选）您可以通过模拟过期日期和时间并匹配几个项目来执行测试。这为您提供了项目的样本列表，并确认有些项目包含随过期时间提供的 TTL 属性名称。

TTL 启用后，当您在 DynamoDB 控制台上查看项目时，TTL 属性被标记为 **TTL**。您可以通过将指针悬停在属性上来查看项目过期的日期和时间。

## 使用 API 启用 DynamoDB TTL
<a name="time-to-live-ttl-how-to-enable-api"></a>

------
#### [ Python ]

您可以使用 [UpdateTimeToLive](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/client/update_time_to_live.html) 操作通过代码启用 TTL。

```
import boto3


def enable_ttl(table_name, ttl_attribute_name):
    """
    Enables TTL on DynamoDB table for a given attribute name
        on success, returns a status code of 200
        on error, throws an exception

    :param table_name: Name of the DynamoDB table
    :param ttl_attribute_name: The name of the TTL attribute being provided to the table.
    """
    try:
        dynamodb = boto3.client('dynamodb')

        # Enable TTL on an existing DynamoDB table
        response = dynamodb.update_time_to_live(
            TableName=table_name,
            TimeToLiveSpecification={
                'Enabled': True,
                'AttributeName': ttl_attribute_name
            }
        )

        # In the returned response, check for a successful status code.
        if response['ResponseMetadata']['HTTPStatusCode'] == 200:
            print("TTL has been enabled successfully.")
        else:
            print(f"Failed to enable TTL, status code {response['ResponseMetadata']['HTTPStatusCode']}")
    except Exception as ex:
        print("Couldn't enable TTL in table %s. Here's why: %s" % (table_name, ex))
        raise


# your values
enable_ttl('your-table-name', 'expirationDate')
```

您可以使用 [DescribeTimeToLive](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/client/describe_time_to_live.html) 操作确认 TTL 已启用，该操作描述了表上的 TTL 状态。`TimeToLive` 状态为 `ENABLED` 或 `DISABLED`。

```
# create a DynamoDB client
dynamodb = boto3.client('dynamodb')

# set the table name
table_name = 'YourTable'

# describe TTL
response = dynamodb.describe_time_to_live(TableName=table_name)
```

------
#### [ JavaScript ]

您可以使用 [UpdateTimeToLiveCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-dynamodb/Class/UpdateTimeToLiveCommand/) 操作通过代码启用 TTL。

```
import { DynamoDBClient, UpdateTimeToLiveCommand } from "@aws-sdk/client-dynamodb";

const enableTTL = async (tableName, ttlAttribute) => {

    const client = new DynamoDBClient({});

    const params = {
        TableName: tableName,
        TimeToLiveSpecification: {
            Enabled: true,
            AttributeName: ttlAttribute
        }
    };

    try {
        const response = await client.send(new UpdateTimeToLiveCommand(params));
        if (response.$metadata.httpStatusCode === 200) {
            console.log(`TTL enabled successfully for table ${tableName}, using attribute name ${ttlAttribute}.`);
        } else {
            console.log(`Failed to enable TTL for table ${tableName}, response object: ${response}`);
        }
        return response;
    } catch (e) {
        console.error(`Error enabling TTL: ${e}`);
        throw e;
    }
};

// call with your own values
enableTTL('ExampleTable', 'exampleTtlAttribute');
```

------

## 使用 AWS CLI 启用生存时间
<a name="time-to-live-ttl-how-to-enable-cli-sdk"></a>

1. 在 `TTLExample` 表上启用 TTL。

   ```
   aws dynamodb update-time-to-live --table-name TTLExample --time-to-live-specification "Enabled=true, AttributeName=ttl"
   ```

1. 在 `TTLExample` 表上描述 TTL。

   ```
   aws dynamodb describe-time-to-live --table-name TTLExample
   {
       "TimeToLiveDescription": {
           "AttributeName": "ttl",
           "TimeToLiveStatus": "ENABLED"
       }
   }
   ```

1. 通过使用 BASH shell 和 `TTLExample` 设置生存时间属性将项目添加至 AWS CLI 表。

   ```
   EXP=`date -d '+5 days' +%s`
   aws dynamodb put-item --table-name "TTLExample" --item '{"id": {"N": "1"}, "ttl": {"N": "'$EXP'"}}'
   ```

此示例从当前日期开始，并在当前日期上增加 5 天来创建过期时间。然后，它将过期时间转换为纪元时间格式，以便最终添加项目到“`TTLExample`”表。

**注意**  
 为生存时间设置过期值的一种方式是计算添加到过期时间的秒数。例如，5 天是 432000 秒。但是，人们通常习惯于从某个日期算起。

获取当前时间的纪元时间格式非常简单，如下例中所示。
+ Linux 终端：`date +%s`
+ Python：`import time; int(time.time())`
+ Java：`System.currentTimeMillis() / 1000L`
+ JavaScript: `Math.floor(Date.now() / 1000)`

## 使用 CloudFormation 启用 DynamoDB TTL
<a name="time-to-live-ttl-how-to-enable-cf"></a>

```
AWSTemplateFormatVersion: "2010-09-09"
Resources:
  TTLExampleTable:
    Type: AWS::DynamoDB::Table
    Description: "A DynamoDB table with TTL Specification enabled"
    Properties:
      AttributeDefinitions:
        - AttributeName: "Album"
          AttributeType: "S"
        - AttributeName: "Artist"
          AttributeType: "S"
      KeySchema:
        - AttributeName: "Album"
          KeyType: "HASH"
        - AttributeName: "Artist"
          KeyType: "RANGE"
      ProvisionedThroughput:
        ReadCapacityUnits: "5"
        WriteCapacityUnits: "5"
      TimeToLiveSpecification:
        AttributeName: "TTLExampleAttribute"
        Enabled: true
```

可以在[此处](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-table-timetolivespecification.html)找到有关在 CloudFormation 模板中使用 TTL 的更多详细信息。

# 在 DynamoDB 中计算生存时间（TTL）
<a name="time-to-live-ttl-before-you-start"></a>

实现 TTL 的常用方法是根据项目的创建时间或上次更新时间为其设置过期时间。这可以通过在 `createdAt` 和 `updatedAt` 时间戳中添加时间来完成。例如，可以将新创建项目的 TTL 设置为 `createdAt` \$1 90 天。项目更新后，TTL 可以重新计算为 `updatedAt` \$1 90 天。

计算出的过期时间必须采用纪元格式，以秒为单位。考虑到过期和删除的情况，TTL 不能超过过去五年。如果您使用任何其他格式，TTL 进程将忽略该项目。如果您根据需要将过期时间设置为将来的某个时间，则项目会在该时间之后过期。例如，假设您将过期时间设置为 1724241326 [即 2024 年 8 月 21 日星期一 11:55:26（UTC）]。该项目会在指定时间后过期。没有最低 TTL 持续时间。您可以将过期时间设置为任何将来的时间，例如从当前时间起 5 分钟。但是，DynamoDB 通常会在过期项目过期后的 48 小时内将其删除，而不是在项目过期后立即删除。

**Topics**
+ [创建一个项目并设置生存时间](#time-to-live-ttl-before-you-start-create)
+ [更新项目并刷新生存时间](#time-to-live-ttl-before-you-start-update)

## 创建一个项目并设置生存时间
<a name="time-to-live-ttl-before-you-start-create"></a>

以下示例演示了如何使用 `expireAt` 作为 TTL 属性名称，来计算创建新项目时的过期时间。赋值语句以变量形式获取当前时间。在示例中，过期时间计算为从当前时间起 90 天。然后将时间转换为纪元格式，并在 TTL 属性中保存为整数数据类型。

以下代码示例展示如何创建设置了 TTL 的项目。

------
#### [ Java ]

**适用于 Java 的 SDK 2.x**  

```
package com.amazon.samplelib.ttl;

import com.amazon.samplelib.CodeSampleUtils;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.PutItemResponse;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * Creates an item in a DynamoDB table with TTL attributes.
 * This class demonstrates how to add TTL expiration timestamps to DynamoDB items.
 */
public class CreateTTL {

    private static final String USAGE =
        """
            Usage:
                <tableName> <primaryKey> <sortKey> <region>
            Where:
                tableName - The Amazon DynamoDB table being queried.
                primaryKey - The name of the primary key. Also known as the hash or partition key.
                sortKey - The name of the sort key. Also known as the range attribute.
                region (optional) - The AWS region that the Amazon DynamoDB table is located in. (Default: us-east-1)
            """;
    private static final int DAYS_TO_EXPIRE = 90;
    private static final int SECONDS_PER_DAY = 24 * 60 * 60;
    private static final String PRIMARY_KEY_ATTR = "primaryKey";
    private static final String SORT_KEY_ATTR = "sortKey";
    private static final String CREATION_DATE_ATTR = "creationDate";
    private static final String EXPIRE_AT_ATTR = "expireAt";
    private static final String SUCCESS_MESSAGE = "%s PutItem operation with TTL successful.";
    private static final String TABLE_NOT_FOUND_ERROR = "Error: The Amazon DynamoDB table \"%s\" can't be found.";

    private final DynamoDbClient dynamoDbClient;

    /**
     * Constructs a CreateTTL instance with the specified DynamoDB client.
     *
     * @param dynamoDbClient The DynamoDB client to use
     */
    public CreateTTL(final DynamoDbClient dynamoDbClient) {
        this.dynamoDbClient = dynamoDbClient;
    }

    /**
     * Constructs a CreateTTL with a default DynamoDB client.
     */
    public CreateTTL() {
        this.dynamoDbClient = null;
    }

    /**
     * Main method to demonstrate creating an item with TTL.
     *
     * @param args Command line arguments
     */
    public static void main(final String[] args) {
        try {
            int result = new CreateTTL().processArgs(args);
            System.exit(result);
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }

    /**
     * Process command line arguments and create an item with TTL.
     *
     * @param args Command line arguments
     * @return 0 if successful, non-zero otherwise
     * @throws ResourceNotFoundException If the table doesn't exist
     * @throws DynamoDbException If an error occurs during the operation
     * @throws IllegalArgumentException If arguments are invalid
     */
    public int processArgs(final String[] args) {
        // Argument validation (remove or replace this line when reusing this code)
        CodeSampleUtils.validateArgs(args, new int[] {3, 4}, USAGE);

        final String tableName = args[0];
        final String primaryKey = args[1];
        final String sortKey = args[2];
        final Region region = Optional.ofNullable(args.length > 3 ? args[3] : null)
            .map(Region::of)
            .orElse(Region.US_EAST_1);

        try (DynamoDbClient ddb = dynamoDbClient != null
            ? dynamoDbClient
            : DynamoDbClient.builder().region(region).build()) {
            final CreateTTL createTTL = new CreateTTL(ddb);
            createTTL.createItemWithTTL(tableName, primaryKey, sortKey);
            return 0;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * Creates an item in the specified table with TTL attributes.
     *
     * @param tableName The name of the table
     * @param primaryKeyValue The value for the primary key
     * @param sortKeyValue The value for the sort key
     * @return The response from the PutItem operation
     * @throws ResourceNotFoundException If the table doesn't exist
     * @throws DynamoDbException If an error occurs during the operation
     */
    public PutItemResponse createItemWithTTL(
        final String tableName, final String primaryKeyValue, final String sortKeyValue) {
        // Get current time in epoch second format
        final long createDate = System.currentTimeMillis() / 1000;

        // Calculate expiration time 90 days from now in epoch second format
        final long expireDate = createDate + (DAYS_TO_EXPIRE * SECONDS_PER_DAY);

        final Map<String, AttributeValue> itemMap = new HashMap<>();
        itemMap.put(
            PRIMARY_KEY_ATTR, AttributeValue.builder().s(primaryKeyValue).build());
        itemMap.put(SORT_KEY_ATTR, AttributeValue.builder().s(sortKeyValue).build());
        itemMap.put(
            CREATION_DATE_ATTR,
            AttributeValue.builder().n(String.valueOf(createDate)).build());
        itemMap.put(
            EXPIRE_AT_ATTR,
            AttributeValue.builder().n(String.valueOf(expireDate)).build());

        final PutItemRequest request =
            PutItemRequest.builder().tableName(tableName).item(itemMap).build();

        try {
            final PutItemResponse response = dynamoDbClient.putItem(request);
            System.out.println(String.format(SUCCESS_MESSAGE, tableName));
            return response;
        } catch (ResourceNotFoundException e) {
            System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
            throw e;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            throw e;
        }
    }
}
```
+  有关 API 详细信息，请参阅《AWS SDK for Java 2.x API Reference》**中的 [PutItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/PutItem)。

------
#### [ JavaScript ]

**SDK for JavaScript（v3）**  

```
import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";

export function createDynamoDBItem(table_name, region, partition_key, sort_key) {
    const client = new DynamoDBClient({
        region: region,
        endpoint: `https://dynamodb.${region}.amazonaws.com`
    });

    // Get the current time in epoch second format
    const current_time = Math.floor(new Date().getTime() / 1000);

    // Calculate the expireAt time (90 days from now) in epoch second format
    const expire_at = Math.floor((new Date().getTime() + 90 * 24 * 60 * 60 * 1000) / 1000);

    // Create DynamoDB item
    const item = {
        'partitionKey': {'S': partition_key},
        'sortKey': {'S': sort_key},
        'createdAt': {'N': current_time.toString()},
        'expireAt': {'N': expire_at.toString()}
    };

    const putItemCommand = new PutItemCommand({
        TableName: table_name,
        Item: item,
        ProvisionedThroughput: {
            ReadCapacityUnits: 1,
            WriteCapacityUnits: 1,
        },
    });

    client.send(putItemCommand, function(err, data) {
        if (err) {
            console.log("Exception encountered when creating item %s, here's what happened: ", data, err);
            throw err;
        } else {
            console.log("Item created successfully: %s.", data);
            return data;
        }
    });
}

// Example usage (commented out for testing)
// createDynamoDBItem('your-table-name', 'us-east-1', 'your-partition-key-value', 'your-sort-key-value');
```
+  有关 API 详细信息，请参阅《适用于 JavaScript 的 AWS SDK API Reference》**中的 [PutItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/PutItemCommand)。

------
#### [ Python ]

**适用于 Python 的 SDK（Boto3）**  

```
from datetime import datetime, timedelta

import boto3


def create_dynamodb_item(table_name, region, primary_key, sort_key):
    """
    Creates a DynamoDB item with an attached expiry attribute.

    :param table_name: Table name for the boto3 resource to target when creating an item
    :param region: string representing the AWS region. Example: `us-east-1`
    :param primary_key: one attribute known as the partition key.
    :param sort_key: Also known as a range attribute.
    :return: Void (nothing)
    """
    try:
        dynamodb = boto3.resource("dynamodb", region_name=region)
        table = dynamodb.Table(table_name)

        # Get the current time in epoch second format
        current_time = int(datetime.now().timestamp())

        # Calculate the expiration time (90 days from now) in epoch second format
        expiration_time = int((datetime.now() + timedelta(days=90)).timestamp())

        item = {
            "primaryKey": primary_key,
            "sortKey": sort_key,
            "creationDate": current_time,
            "expireAt": expiration_time,
        }
        response = table.put_item(Item=item)

        print("Item created successfully.")
        return response
    except Exception as e:
        print(f"Error creating item: {e}")
        raise e


# Use your own values
create_dynamodb_item(
    "your-table-name", "us-west-2", "your-partition-key-value", "your-sort-key-value"
)
```
+  有关 API 详细信息，请参阅《AWS SDK for Python (Boto3) API Reference》**中的 [PutItem](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/PutItem)。

------

## 更新项目并刷新生存时间
<a name="time-to-live-ttl-before-you-start-update"></a>

此示例是[上一节](#time-to-live-ttl-before-you-start-create)所讲示例的延续。如果更新了项目，则可以重新计算过期时间。以下示例将 `expireAt` 时间戳重新计算为自当前时间起 90 天。

以下代码示例演示了如何更新项目的 TTL。

------
#### [ Java ]

**适用于 Java 的 SDK 2.x**  
更新表中现有 DynamoDB 项目的 TTL  

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemResponse;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

    public UpdateItemResponse updateItemWithTTL(
        final String tableName, final String primaryKeyValue, final String sortKeyValue) {
        // Get current time in epoch second format
        final long currentTime = System.currentTimeMillis() / 1000;

        // Calculate expiration time 90 days from now in epoch second format
        final long expireDate = currentTime + (DAYS_TO_EXPIRE * SECONDS_PER_DAY);

        // Create the key map for the item to update
        final Map<String, AttributeValue> keyMap = new HashMap<>();
        keyMap.put(PRIMARY_KEY_ATTR, AttributeValue.builder().s(primaryKeyValue).build());
        keyMap.put(SORT_KEY_ATTR, AttributeValue.builder().s(sortKeyValue).build());

        // Create the expression attribute values
        final Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
        expressionAttributeValues.put(
            ":c", AttributeValue.builder().n(String.valueOf(currentTime)).build());
        expressionAttributeValues.put(
            ":e", AttributeValue.builder().n(String.valueOf(expireDate)).build());

        final UpdateItemRequest request = UpdateItemRequest.builder()
            .tableName(tableName)
            .key(keyMap)
            .updateExpression(UPDATE_EXPRESSION)
            .expressionAttributeValues(expressionAttributeValues)
            .build();

        try {
            final UpdateItemResponse response = dynamoDbClient.updateItem(request);
            System.out.println(String.format(SUCCESS_MESSAGE, tableName));
            return response;
        } catch (ResourceNotFoundException e) {
            System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
            throw e;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            throw e;
        }
    }
```
+  有关 API 详细信息，请参阅《AWS SDK for Java 2.x API Reference》**中的 [UpdateItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateItem)。

------
#### [ JavaScript ]

**SDK for JavaScript（v3）**  

```
import { DynamoDBClient, UpdateItemCommand } from "@aws-sdk/client-dynamodb";
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";

export const updateItem = async (tableName, partitionKey, sortKey, region = 'us-east-1') => {
    const client = new DynamoDBClient({
        region: region,
        endpoint: `https://dynamodb.${region}.amazonaws.com`
    });

    const currentTime = Math.floor(Date.now() / 1000);
    const expireAt = Math.floor((Date.now() + 90 * 24 * 60 * 60 * 1000) / 1000);

    const params = {
        TableName: tableName,
        Key: marshall({
            partitionKey: partitionKey,
            sortKey: sortKey
        }),
        UpdateExpression: "SET updatedAt = :c, expireAt = :e",
        ExpressionAttributeValues: marshall({
            ":c": currentTime,
            ":e": expireAt
        }),
    };

    try {
        const data = await client.send(new UpdateItemCommand(params));
        const responseData = unmarshall(data.Attributes);
        console.log("Item updated successfully: %s", responseData);
        return responseData;
    } catch (err) {
        console.error("Error updating item:", err);
        throw err;
    }
}

// Example usage (commented out for testing)
// updateItem('your-table-name', 'your-partition-key-value', 'your-sort-key-value');
```
+  有关 API 详细信息，请参阅《适用于 JavaScript 的 AWS SDK API Reference》**中的 [UpdateItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/UpdateItemCommand)。

------
#### [ Python ]

**适用于 Python 的 SDK（Boto3）**  

```
from datetime import datetime, timedelta

import boto3


def update_dynamodb_item(table_name, region, primary_key, sort_key):
    """
    Update an existing DynamoDB item with a TTL.
    :param table_name: Name of the DynamoDB table
    :param region: AWS Region of the table - example `us-east-1`
    :param primary_key: one attribute known as the partition key.
    :param sort_key: Also known as a range attribute.
    :return: Void (nothing)
    """
    try:
        # Create the DynamoDB resource.
        dynamodb = boto3.resource("dynamodb", region_name=region)
        table = dynamodb.Table(table_name)

        # Get the current time in epoch second format
        current_time = int(datetime.now().timestamp())

        # Calculate the expireAt time (90 days from now) in epoch second format
        expire_at = int((datetime.now() + timedelta(days=90)).timestamp())

        table.update_item(
            Key={"partitionKey": primary_key, "sortKey": sort_key},
            UpdateExpression="set updatedAt=:c, expireAt=:e",
            ExpressionAttributeValues={":c": current_time, ":e": expire_at},
        )

        print("Item updated successfully.")
    except Exception as e:
        print(f"Error updating item: {e}")


# Replace with your own values
update_dynamodb_item(
    "your-table-name", "us-west-2", "your-partition-key-value", "your-sort-key-value"
)
```
+  有关 API 详细信息，请参阅《AWS SDK for Python（Boto3）API Reference》**中的 [UpdateItem](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/UpdateItem)。

------

本简介中讨论的 TTL 示例演示了一种确保表中仅保留最近更新的项目的方法。更新的项目会延长寿命，而创建后未更新的项目将过期并被免费删除，从而减少存储空间并保持表整洁。

# 使用过期项目和生存时间（TTL）
<a name="ttl-expired-items"></a>

可以通过读取和写入操作筛选待删除的过期项目。这在过期数据不再有效且不会使用的情况下很有用。如果未将其筛选出来，它们将继续显示在读取和写入操作中，直到它们被后台进程删除。

**注意**  
这些项目在被删除之前仍会计入存储和读取费用中。

可以在 DynamoDB Streams 中识别 TTL 删除，但只能在执行删除的区域中识别。对于删除复制到的区域，复制到全局表区域的 TTL 删除在 DynamoDB Streams 中无法识别。

## 从读取操作中筛选过期项目
<a name="ttl-expired-items-filter"></a>

对于诸如[扫描](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html)和[查询](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html)之类的读取操作，筛选表达式可以筛选出待删除的过期项目。如下面的代码段所示，筛选表达式可以筛选出 TTL 时间等于或小于当前时间的项目。例如，Python SDK 代码包含一个赋值语句，该语句将当前时间作为变量（`now`）获取，并将其转换为纪元时间格式 `int`。

以下代码示例演示了如何查询 TTL 项目。

------
#### [ Java ]

**SDK for Java 2.x**  
查询对表达式进行了筛选，以使用AWS SDK for Java 2.x 在 DynamoDB 表中收集 TTL 项目。  

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.QueryRequest;
import software.amazon.awssdk.services.dynamodb.model.QueryResponse;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;

import java.util.Map;
import java.util.Optional;

        final QueryRequest request = QueryRequest.builder()
            .tableName(tableName)
            .keyConditionExpression(KEY_CONDITION_EXPRESSION)
            .filterExpression(FILTER_EXPRESSION)
            .expressionAttributeNames(expressionAttributeNames)
            .expressionAttributeValues(expressionAttributeValues)
            .build();

        try (DynamoDbClient ddb = dynamoDbClient != null
            ? dynamoDbClient
            : DynamoDbClient.builder().region(region).build()) {
            final QueryResponse response = ddb.query(request);
            System.out.println("Query successful. Found " + response.count() + " items that have not expired yet.");

            // Print each item
            response.items().forEach(item -> {
                System.out.println("Item: " + item);
            });

            return 0;
        } catch (ResourceNotFoundException e) {
            System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
            throw e;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            throw e;
        }
```
+  有关 API 详细信息，请参阅《AWS SDK for Java 2.x API Reference》**中的 [Query](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/Query)。

------
#### [ JavaScript ]

**SDK for JavaScript（v3）**  
查询对表达式进行了筛选，以使用适用于 JavaScript 的 AWS SDK 在 DynamoDB 表中收集 TTL 项目。  

```
import { DynamoDBClient, QueryCommand } from "@aws-sdk/client-dynamodb";
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";

export const queryFiltered = async (tableName, primaryKey, region = 'us-east-1') => {
    const client = new DynamoDBClient({
        region: region,
        endpoint: `https://dynamodb.${region}.amazonaws.com`
    });

    const currentTime = Math.floor(Date.now() / 1000);

    const params = {
        TableName: tableName,
        KeyConditionExpression: "#pk = :pk",
        FilterExpression: "#ea > :ea",
        ExpressionAttributeNames: {
            "#pk": "primaryKey",
            "#ea": "expireAt"
        },
        ExpressionAttributeValues: marshall({
            ":pk": primaryKey,
            ":ea": currentTime
        })
    };

    try {
        const { Items } = await client.send(new QueryCommand(params));
        Items.forEach(item => {
            console.log(unmarshall(item))
        });
        return Items;
    } catch (err) {
        console.error(`Error querying items: ${err}`);
        throw err;
    }
}

// Example usage (commented out for testing)
// queryFiltered('your-table-name', 'your-partition-key-value');
```
+  有关 API 详细信息，请参阅《适用于 JavaScript 的 AWS SDK API Reference》**中的 [Query](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/QueryCommand)。

------
#### [ Python ]

**适用于 Python 的 SDK（Boto3）**  
查询对表达式进行了筛选，以使用适用于 Python (Boto3) 的 AWS SDK 在 DynamoDB 表中收集 TTL 项目。  

```
from datetime import datetime

import boto3


def query_dynamodb_items(table_name, partition_key):
    """

    :param table_name: Name of the DynamoDB table
    :param partition_key:
    :return:
    """
    try:
        # Initialize a DynamoDB resource
        dynamodb = boto3.resource("dynamodb", region_name="us-east-1")

        # Specify your table
        table = dynamodb.Table(table_name)

        # Get the current time in epoch format
        current_time = int(datetime.now().timestamp())

        # Perform the query operation with a filter expression to exclude expired items
        # response = table.query(
        #    KeyConditionExpression=boto3.dynamodb.conditions.Key('partitionKey').eq(partition_key),
        #    FilterExpression=boto3.dynamodb.conditions.Attr('expireAt').gt(current_time)
        # )
        response = table.query(
            KeyConditionExpression=dynamodb.conditions.Key("partitionKey").eq(partition_key),
            FilterExpression=dynamodb.conditions.Attr("expireAt").gt(current_time),
        )

        # Print the items that are not expired
        for item in response["Items"]:
            print(item)

    except Exception as e:
        print(f"Error querying items: {e}")


# Call the function with your values
query_dynamodb_items("Music", "your-partition-key-value")
```
+  有关 API 详细信息，请参阅《AWS SDK for Python (Boto3) API Reference》**中的 [Query](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/Query)。

------

## 有条件地写入过期项目
<a name="ttl-expired-items-conditional-write"></a>

条件表达式可用于避免写入过期项目。下面的代码段是一个有条件的更新，用于检查过期时间是否大于当前时间。如果为 true，则写入操作将继续。

以下代码示例演示了如何有条件地更新项目的 TTL。

------
#### [ Java ]

**适用于 Java 的 SDK 2.x**  
使用条件更新表中现有 DynamoDB 项目的 TTL。  

```
package com.amazon.samplelib.ttl;

import com.amazon.samplelib.CodeSampleUtils;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemResponse;

import java.util.Map;
import java.util.Optional;

/**
 * Updates an item in a DynamoDB table with TTL attributes using a conditional expression.
 * This class demonstrates how to conditionally update TTL expiration timestamps.
 */
public class UpdateTTLConditional {

    private static final String USAGE =
        """
            Usage:
                <tableName> <primaryKey> <sortKey> <region>
            Where:
                tableName - The Amazon DynamoDB table being queried.
                primaryKey - The name of the primary key. Also known as the hash or partition key.
                sortKey - The name of the sort key. Also known as the range attribute.
                region (optional) - The AWS region that the Amazon DynamoDB table is located in. (Default: us-east-1)
            """;
    private static final int DAYS_TO_EXPIRE = 90;
    private static final int SECONDS_PER_DAY = 24 * 60 * 60;
    private static final String PRIMARY_KEY_ATTR = "primaryKey";
    private static final String SORT_KEY_ATTR = "sortKey";
    private static final String UPDATED_AT_ATTR = "updatedAt";
    private static final String EXPIRE_AT_ATTR = "expireAt";
    private static final String UPDATE_EXPRESSION = "SET " + UPDATED_AT_ATTR + "=:c, " + EXPIRE_AT_ATTR + "=:e";
    private static final String CONDITION_EXPRESSION = "attribute_exists(" + PRIMARY_KEY_ATTR + ")";
    private static final String SUCCESS_MESSAGE = "%s UpdateItem operation with TTL successful.";
    private static final String CONDITION_FAILED_MESSAGE = "Condition check failed. Item does not exist.";
    private static final String TABLE_NOT_FOUND_ERROR = "Error: The Amazon DynamoDB table \"%s\" can't be found.";

    private final DynamoDbClient dynamoDbClient;

    /**
     * Constructs an UpdateTTLConditional with a default DynamoDB client.
     */
    public UpdateTTLConditional() {
        this.dynamoDbClient = null;
    }

    /**
     * Constructs an UpdateTTLConditional with the specified DynamoDB client.
     *
     * @param dynamoDbClient The DynamoDB client to use
     */
    public UpdateTTLConditional(final DynamoDbClient dynamoDbClient) {
        this.dynamoDbClient = dynamoDbClient;
    }

    /**
     * Main method to demonstrate conditionally updating an item with TTL.
     *
     * @param args Command line arguments
     */
    public static void main(final String[] args) {
        try {
            int result = new UpdateTTLConditional().processArgs(args);
            System.exit(result);
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }

    /**
     * Process command line arguments and conditionally update an item with TTL.
     *
     * @param args Command line arguments
     * @return 0 if successful, non-zero otherwise
     * @throws ResourceNotFoundException If the table doesn't exist
     * @throws DynamoDbException If an error occurs during the operation
     * @throws IllegalArgumentException If arguments are invalid
     */
    public int processArgs(final String[] args) {
        // Argument validation (remove or replace this line when reusing this code)
        CodeSampleUtils.validateArgs(args, new int[] {3, 4}, USAGE);

        final String tableName = args[0];
        final String primaryKey = args[1];
        final String sortKey = args[2];
        final Region region = Optional.ofNullable(args.length > 3 ? args[3] : null)
            .map(Region::of)
            .orElse(Region.US_EAST_1);

        // Get current time in epoch second format
        final long currentTime = System.currentTimeMillis() / 1000;

        // Calculate expiration time 90 days from now in epoch second format
        final long expireDate = currentTime + (DAYS_TO_EXPIRE * SECONDS_PER_DAY);

        // Create the key map for the item to update
        final Map<String, AttributeValue> keyMap = Map.of(
            PRIMARY_KEY_ATTR, AttributeValue.builder().s(primaryKey).build(),
            SORT_KEY_ATTR, AttributeValue.builder().s(sortKey).build());

        // Create the expression attribute values
        final Map<String, AttributeValue> expressionAttributeValues = Map.of(
            ":c", AttributeValue.builder().n(String.valueOf(currentTime)).build(),
            ":e", AttributeValue.builder().n(String.valueOf(expireDate)).build());

        final UpdateItemRequest request = UpdateItemRequest.builder()
            .tableName(tableName)
            .key(keyMap)
            .updateExpression(UPDATE_EXPRESSION)
            .conditionExpression(CONDITION_EXPRESSION)
            .expressionAttributeValues(expressionAttributeValues)
            .build();

        try (DynamoDbClient ddb = dynamoDbClient != null
            ? dynamoDbClient
            : DynamoDbClient.builder().region(region).build()) {
            final UpdateItemResponse response = ddb.updateItem(request);
            System.out.println(String.format(SUCCESS_MESSAGE, tableName));
            return 0;
        } catch (ConditionalCheckFailedException e) {
            System.err.println(CONDITION_FAILED_MESSAGE);
            throw e;
        } catch (ResourceNotFoundException e) {
            System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
            throw e;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            throw e;
        }
    }
}
```
+  有关 API 详细信息，请参阅《AWS SDK for Java 2.x API Reference》**中的 [UpdateItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateItem)。

------
#### [ JavaScript ]

**SDK for JavaScript（v3）**  
使用条件更新表中现有 DynamoDB 项目的 TTL。  

```
import { DynamoDBClient, UpdateItemCommand } from "@aws-sdk/client-dynamodb";
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";

export const updateItemConditional = async (tableName, partitionKey, sortKey, region = 'us-east-1', newAttribute = 'default-value') => {
    const client = new DynamoDBClient({
        region: region,
        endpoint: `https://dynamodb.${region}.amazonaws.com`
    });

    const currentTime = Math.floor(Date.now() / 1000);

    const params = {
        TableName: tableName,
        Key: marshall({
            artist: partitionKey,
            album: sortKey
        }),
        UpdateExpression: "SET newAttribute = :newAttribute",
        ConditionExpression: "expireAt > :expiration",
        ExpressionAttributeValues: marshall({
            ':newAttribute': newAttribute,
            ':expiration': currentTime
        }),
        ReturnValues: "ALL_NEW"
    };

    try {
        const response = await client.send(new UpdateItemCommand(params));
        const responseData = unmarshall(response.Attributes);
        console.log("Item updated successfully: ", responseData);
        return responseData;
    } catch (error) {
        if (error.name === "ConditionalCheckFailedException") {
            console.log("Condition check failed: Item's 'expireAt' is expired.");
        } else {
            console.error("Error updating item: ", error);
        }
        throw error;
    }
};

// Example usage (commented out for testing)
// updateItemConditional('your-table-name', 'your-partition-key-value', 'your-sort-key-value');
```
+  有关 API 详细信息，请参阅《适用于 JavaScript 的 AWS SDK API Reference》**中的 [UpdateItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/UpdateItemCommand)。

------
#### [ Python ]

**适用于 Python 的 SDK（Boto3）**  
使用条件更新表中现有 DynamoDB 项目的 TTL。  

```
from datetime import datetime, timedelta

import boto3
from botocore.exceptions import ClientError


def update_dynamodb_item_ttl(table_name, region, primary_key, sort_key, ttl_attribute):
    """
    Updates an existing record in a DynamoDB table with a new or updated TTL attribute.

    :param table_name: Name of the DynamoDB table
    :param region: AWS Region of the table - example `us-east-1`
    :param primary_key: one attribute known as the partition key.
    :param sort_key: Also known as a range attribute.
    :param ttl_attribute: name of the TTL attribute in the target DynamoDB table
    :return:
    """
    try:
        dynamodb = boto3.resource("dynamodb", region_name=region)
        table = dynamodb.Table(table_name)

        # Generate updated TTL in epoch second format
        updated_expiration_time = int((datetime.now() + timedelta(days=90)).timestamp())

        # Define the update expression for adding/updating a new attribute
        update_expression = "SET newAttribute = :val1"

        # Define the condition expression for checking if 'expireAt' is not expired
        condition_expression = "expireAt > :val2"

        # Define the expression attribute values
        expression_attribute_values = {":val1": ttl_attribute, ":val2": updated_expiration_time}

        response = table.update_item(
            Key={"primaryKey": primary_key, "sortKey": sort_key},
            UpdateExpression=update_expression,
            ConditionExpression=condition_expression,
            ExpressionAttributeValues=expression_attribute_values,
        )

        print("Item updated successfully.")
        return response["ResponseMetadata"]["HTTPStatusCode"]  # Ideally a 200 OK
    except ClientError as e:
        if e.response["Error"]["Code"] == "ConditionalCheckFailedException":
            print("Condition check failed: Item's 'expireAt' is expired.")
        else:
            print(f"Error updating item: {e}")
    except Exception as e:
        print(f"Error updating item: {e}")


# replace with your values
update_dynamodb_item_ttl(
    "your-table-name",
    "us-east-1",
    "your-partition-key-value",
    "your-sort-key-value",
    "your-ttl-attribute-value",
)
```
+  有关 API 详细信息，请参阅《AWS SDK for Python（Boto3）API Reference》**中的 [UpdateItem](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/UpdateItem)。

------

## 识别 DynamoDB Streams 中已删除的项目
<a name="ttl-expired-items-identifying"></a>

流记录包含用户身份字段`Records[<index>].userIdentity`。被 TTL 过程删除的项目包含以下字段：

```
Records[<index>].userIdentity.type
"Service"

Records[<index>].userIdentity.principalId
"dynamodb.amazonaws.com"
```

以下 JSON 显示单个流记录的相关部分：

```
"Records": [ 
  { 
	... 
		"userIdentity": {
		"type": "Service", 
      	"principalId": "dynamodb.amazonaws.com" 
   	} 
   ... 
	} 
]
```

# 在 DynamoDB 中查询表
<a name="Query"></a>

您可以使用 Amazon DynamoDB 中的 `Query` API 操作基于主键值查找项目。

您必须提供分区键属性的名称以及该属性的一个值。`Query` 将返回具有该分区键值的所有项目。（可选）您可以提供排序键属性，并使用比较运算符来细化搜索结果。

有关如何使用 `Query` 的更多信息，例如请求语法、响应参数和其他示例，请参阅《Amazon DynamoDB API 参考》**中的[查询](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html)。

**Topics**
+ [DynamoDB 中的查询操作的键条件表达式](Query.KeyConditionExpressions.md)
+ [DynamoDB 中的查询操作的筛选表达式](Query.FilterExpression.md)
+ [在 DynamoDB 中对表查询结果分页](Query.Pagination.md)
+ [在 DynamoDB 中使用查询操作的其他分面](Query.Other.md)

# DynamoDB 中的查询操作的键条件表达式
<a name="Query.KeyConditionExpressions"></a>

您可以在键条件表达式中使用任意属性名称，前提是第一个字符是 `a-z` 或 `A-Z`，其余字符（从第二个字符开始，如果存在）为 `a-z`、`A-Z` 或 `0-9`。此外，属性名称不得为 DynamoDB 保留字。（有关这些保留关键字的完整列表，请参阅[DynamoDB 中的保留字](ReservedWords.md)。） 如果属性名称不满足这些要求，则您必须将表达式属性名称定义为占位符。有关更多信息，请参阅 [DynamoDB 中的表达式属性名称（别名）](Expressions.ExpressionAttributeNames.md)。

对于具有给定分区键值的项目，DynamoDB 会将这些项目存储在紧邻位置并按照排序键值对其进行排序。在 `Query` 操作中，DynamoDB 按照排序顺序检索项目，然后使用 `KeyConditionExpression` 和可能存在的任何 `FilterExpression` 处理项目。只有在此时才会将 `Query` 结果发送回客户端。

`Query` 操作始终返回结果集。如果未找到匹配的项目，结果集将为空。

`Query` 结果始终按排序键值排序。如果排序键的数据类型为 `Number`，则按照数值顺序返回结果。否则，按照 UTF-8 字节的顺序返回结果。默认情况下，系统按升序排序。要颠倒顺序，请将 `ScanIndexForward` 参数设置为 `false`。

单个 `Query` 操作最多可检索 1 MB 的数据。在向结果应用任何 `FilterExpression` 或 `ProjectionExpression` 之前，将应用此限制。如果 `LastEvaluatedKey` 包含在响应中且为非 null 值，则您必须为结果集分页（请参阅[在 DynamoDB 中对表查询结果分页](Query.Pagination.md)）。

## 键条件表达式示例
<a name="Query.KeyConditionExpressions-example"></a>

要指定搜索条件，请使用*键条件表达式*—用于确定要从表或索引中读取的项目的字符串。

您必须指定分区键名称和值作为等式条件。无法在键条件表达式中使用非键属性。

您可选择为排序键提供另一个条件（如果有）。排序键条件必须使用下列比较运算符之一：
+ `a = b` — 如果属性 *a* 等于值 *b*，则为 true
+ `a < b` — 如果 *a* 小于 *b*，则为 true
+ `a <= b` — 如果 *a* 小于等于 *b*，则为 true
+ `a > b` — 如果 *a* 大于 *b*，则为 true
+ `a >= b` — 如果 *a* 大于等于 *b*，则为 true
+ `a BETWEEN b AND c` — 如果 *a* 大于或等于 *b*，且小于或等于 *c*，则为 true。

以下函数也受支持：
+ `begins_with (a, substr)` — 如果属性 `a` 的值以特定子字符串开头，则为 true。

以下 AWS Command Line Interface (AWS CLI) 示例将演示键条件表达式的用法。这些表达式使用占位符（例如 `:name` 和 `:sub`）而不是实际的值。有关更多信息，请参阅[DynamoDB 中的表达式属性名称（别名）](Expressions.ExpressionAttributeNames.md)和[在 DynamoDB 中使用表达式属性值](Expressions.ExpressionAttributeValues.md)。

**Example**  
在 `Thread` 表中查询特定的 `ForumName`（分区键）。具有 `ForumName` 值的所有项目将由查询进行读取，因为排序键 (`Subject`) 未包括在 `KeyConditionExpression` 中。  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :name" \
    --expression-attribute-values  '{":name":{"S":"Amazon DynamoDB"}}'
```

**Example**  
在 `Thread` 表中查询特定的 `ForumName`（分区键），但这一次仅返回具有给定 `Subject`（排序键）的项目。  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :name and Subject = :sub" \
    --expression-attribute-values  file://values.json
```
`--expression-attribute-values` 的参数存储在 `values.json` 文件中。  

```
{
    ":name":{"S":"Amazon DynamoDB"},
    ":sub":{"S":"DynamoDB Thread 1"}
}
```

**Example**  
在 `Reply` 表中查询特定的 `Id`（分区键），但仅返回其 `ReplyDateTime`（排序键）以特定字符开头的项目。  

```
aws dynamodb query \
    --table-name Reply \
    --key-condition-expression "Id = :id and begins_with(ReplyDateTime, :dt)" \
    --expression-attribute-values  file://values.json
```
`--expression-attribute-values` 的参数存储在 `values.json` 文件中。  

```
{
    ":id":{"S":"Amazon DynamoDB#DynamoDB Thread 1"},
    ":dt":{"S":"2015-09"}
}
```

# DynamoDB 中的查询操作的筛选表达式
<a name="Query.FilterExpression"></a>

如果您需要进一步细化 `Query` 结果，则可以选择性地提供筛选表达式。*筛选表达式*可确定 `Query` 结果中应返回给您的项目。所有其他结果将会丢弃。

筛选表达式在 `Query` 已完成但结果尚未返回时应用。因此，无论是否存在筛选表达式，`Query` 都将占用同等数量的读取容量。

`Query` 操作最多可检索 1 MB 的数据。此限制在计算筛选表达式之前应用。

筛选表达式不得包含分区键或排序键属性。您需要在关键字条件表达式而不是筛选表达式中指定这些属性。

筛选表达式的语法与关键条件表达式的语法相似。筛选表达式可使用的比较运算符、函数和逻辑运算符与关键条件表达式可使用的相同。此外，筛选表达式可以使用不等于运算符 (`<>`)、`OR` 运算符、`CONTAINS` 运算符、`IN` 运算符、`BEGINS_WITH` 运算符、`BETWEEN` 运算符、`EXISTS` 运算符和 `SIZE` 运算符。有关更多信息，请参阅[DynamoDB 中的查询操作的键条件表达式](Query.KeyConditionExpressions.md)和[筛选条件和条件表达式的语法](Expressions.OperatorsAndFunctions.md#Expressions.OperatorsAndFunctions.Syntax)。

**Example**  
以下 AWS CLI 示例在 `Thread` 表中查询特定 `ForumName`（分区键）和 `Subject`（排序键）。在找到的项目中，只返回最常用的讨论线程，换句话说，只有那些具有超过一定数量 `Views` 的线程。  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :fn and Subject begins_with :sub" \
    --filter-expression "#v >= :num" \
    --expression-attribute-names '{"#v": "Views"}' \
    --expression-attribute-values file://values.json
```
`--expression-attribute-values` 的参数存储在 `values.json` 文件中。  

```
{
    ":fn":{"S":"Amazon DynamoDB"},
    ":sub":{"S":"DynamoDB Thread 1"},
    ":num":{"N":"3"}
}
```
请注意，`Views` 在 DynamoDB 中是一个保留字（请参阅 [DynamoDB 中的保留字](ReservedWords.md)），因此本示例使用 `#v` 作为占位符。有关更多信息，请参阅 [DynamoDB 中的表达式属性名称（别名）](Expressions.ExpressionAttributeNames.md)。

**注意**  
筛选表达式将从 `Query` 结果集中删除项目。在您预计会检索到大量项目并且还需要丢弃其中大多数项目的情况下，请尽量避免使用 `Query`。

# 在 DynamoDB 中对表查询结果分页
<a name="Query.Pagination"></a>

DynamoDB *分页*来自 `Query` 操作的结果。利用分页，`Query` 结果将分成若干“页”大小为 1 MB（或更小）的数据。应用程序可以先处理第一页结果，然后处理第二页结果，依此类推。

单次 `Query` 只会返回符合 1 MB 大小限制的结果集。要确定是否存在更多结果，并一次检索一页结果，应用程序应执行以下操作：

1. 检查低级别 `Query` 结果：
   + 如果结果包含 `LastEvaluatedKey` 元素并且非空，请继续步骤 2。
   + 如果结果中*没有* `LastEvaluatedKey`，则表示没有其他要检索的项目。

1. 使用相同的 `KeyConditionExpression` 构造 `Query`。但是，此次获取来自步骤 1 的 `LastEvaluatedKey` 值，并将其用作新 `ExclusiveStartKey` 请求中的 `Query` 参数。

1. 运行新的 `Query` 请求。

1. 前往步骤 1。

换言之，`LastEvaluatedKey` 响应中的 `Query` 应该用作下一 `ExclusiveStartKey` 请求的 `Query`。如果 `LastEvaluatedKey` 响应中没有 `Query` 元素，则表示您已检索最后一页结果。如果 `LastEvaluatedKey` 不为空，并不一定意味着结果集中有更多数据。检查 `LastEvaluatedKey` 是否为空是确定您是否已到达结果集末尾的唯一方式。

您可以使用 AWS CLI 查看此行为。AWS CLI 向 DynamoDB 反复发送低级别 `Query` 请求，直到请求中不再有 `LastEvaluatedKey`。考虑以下 AWS CLI 示例，此示例检索特定年份的电影标题。

```
aws dynamodb query --table-name Movies \
    --projection-expression "title" \
    --key-condition-expression "#y = :yyyy" \
    --expression-attribute-names '{"#y":"year"}' \
    --expression-attribute-values '{":yyyy":{"N":"1993"}}' \
    --page-size 5 \
    --debug
```

通常，AWS CLI 自动处理分页。但是，在此例中，AWS CLI `--page-size` 参数限制了每页项目数。`--debug` 参数输出有关请求和响应的低级别信息。

如果您运行该示例，DynamoDB 的首次响应类似如下内容。

```
2017-07-07 11:13:15,603 - MainThread - botocore.parsers - DEBUG - Response body:
b'{"Count":5,"Items":[{"title":{"S":"A Bronx Tale"}},
{"title":{"S":"A Perfect World"}},{"title":{"S":"Addams Family Values"}},
{"title":{"S":"Alive"}},{"title":{"S":"Benny & Joon"}}],
"LastEvaluatedKey":{"year":{"N":"1993"},"title":{"S":"Benny & Joon"}},
"ScannedCount":5}'
```

响应中的 `LastEvaluatedKey` 指示并未检索所有项目。随后，AWS CLI 会将另一个 `Query` 请求发送到 DynamoDB。此请求和响应模式继续，直到收到最终响应。

```
2017-07-07 11:13:16,291 - MainThread - botocore.parsers - DEBUG - Response body:
b'{"Count":1,"Items":[{"title":{"S":"What\'s Eating Gilbert Grape"}}],"ScannedCount":1}'
```

如果不存在 `LastEvaluatedKey`，则表示没有其他要检索的项目。

**注意**  
AWS SDK 处理低级别的 DynamoDB 响应（包括是否存在 `LastEvaluatedKey`），并提供各种抽象概念对 `Query` 结果进行分页。例如，适用于 Java 的 SDK 文档接口提供 `java.util.Iterator` 支持，以便您能够一次处理一个结果。  
对于各种编程语言的代码示例，请参阅本地化的 [Amazon DynamoDB 入门指南](https://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/)和 AWS SDK 文档。

此外，您还可以通过使用 `Query` 操作的 `Limit` 参数来限制结果集中的项目数，以此减少页面大小。

有关用 DynamoDB 查询的更多信息，请参阅[在 DynamoDB 中查询表](Query.md)。

# 在 DynamoDB 中使用查询操作的其他分面
<a name="Query.Other"></a>

此部分介绍了 DynamoDB 查询操作的其他方面，包括限制结果大小、计算已扫描项目与已返回项目的数量、监控读取容量消耗以及控制读取一致性。

## 限制结果集中的项目数
<a name="Query.Limit"></a>

使用 `Query` 操作，您可以限制它读取的项目数。为此，请将 `Limit` 参数设置为您需要的最大项目数。

例如，假设您对某个表进行 `Query`，`Limit` 值为 `6`，并且没有筛选表达式。`Query` 结果将包含表中与请求中的键条件表达式匹配的前 6 个项目。

现在假设您向 `Query` 添加了一个筛选表达式。在这种情况下，DynamoDB 最多可读取六个项目，然后仅返回与筛选表达式匹配的项目。最终 `Query` 结果包含六个或更少的项目，即使更多项目（如果 DynamoDB 继续读取更多项目）与过滤表达式匹配，也是如此。

## 对结果中的项目进行计数
<a name="Query.Count"></a>

除了与您的条件匹配的项目之外，`Query` 响应还包含以下元素：
+ `ScannedCount` — 在应用筛选表达式（如果有）*之前*，与关键字条件表达式匹配的项目的数量。
+ `Count` — 在应用筛选表达式（如果有）*之后*，剩余的项目数量。

**注意**  
如果您不使用筛选表达式，那么 `ScannedCount` 和 `Count` 具有相同的值。

如果 `Query` 结果集的大小大于 1 MB，则 `ScannedCount` 和 `Count` 将仅表示项目总数的部分计数。您需要执行多次 `Query` 操作才能检索所有结果（请参阅[在 DynamoDB 中对表查询结果分页](Query.Pagination.md)）。

所有 `Query` 响应都将包含由该特定 `ScannedCount` 请求处理的项目的 `Count` 和 `Query`。要获取所有 `Query` 请求的总和，您可以对 `ScannedCount` 和 `Count` 记录流水账。

## 查询占用的容量单位
<a name="Query.CapacityUnits"></a>

您可以对任何表或二级索引进行 `Query`，只要您提供分区键属性的名称和该属性的单个值即可。`Query` 返回具有该分区键值的所有项目。（可选）您可以提供排序键属性，并使用比较运算符来细化搜索结果。`Query`API 操作将消耗读取容量单位，如下所示。


****  

| 如果对...进行 `Query` | DynamoDB 将占用...的读取容量单位 | 
| --- | --- | 
| 表 | 表的预置读取容量。 | 
| 全局二级索引 | 索引的预置读取容量。 | 
| 本地二级索引 | 基表的预置读取容量。 | 

默认情况下，`Query` 操作不会返回任何有关它占用的读取容量大小的数据。但是，您可在 `ReturnConsumedCapacity` 请求中指定 `Query` 参数以获取此信息。下面是 `ReturnConsumedCapacity` 的有效设置：
+ `NONE` — 不返回任何已占用容量数据。（这是默认值。）
+ `TOTAL` — 响应包含占用的读取容量单位的总数。
+ `INDEXES` — 响应显示占用的读取容量单位的总数，以及访问的每个表和索引的占用容量。

DynamoDB 将基于项目数量以及这些项目的大小，而不是基于返回到应用程序的数据量来计算消耗的读取容量单位数。因此，无论您是请求所有属性（默认行为）还是只请求部分属性（使用投影表达式），占用的容量单位数都是相同的。无论您是否使用筛选表达式，该数值也都是一样的。`Query` 使用最小的读取容量单位，来为高达 4 KB 的项目每秒执行一次强一致性读取，或每秒执行两次最终一致性读取。如果您需要读取大于 4KB 的项目，DynamoDB 需要额外的读取请求单位。空表和分区键数量稀疏的超大表，可能会有在超出查询的数据量后对一些额外的 RCU 收费的情况。这包括处理 `Query` 请求的费用，即使不存在数据也是如此。

## 查询的读取一致性
<a name="Query.ReadConsistency"></a>

默认情况下，`Query` 操作将执行最终一致性读取。这意味着 `Query` 结果可能无法反映由最近完成的 `PutItem` 或 `UpdateItem` 操作导致的更改。有关更多信息，请参阅 [DynamoDB 读取一致性](HowItWorks.ReadConsistency.md)。

如果您需要强一致性读取，请在 `ConsistentRead` 请求中将 `true` 参数设置为 `Query`。

# 在 DynamoDB 中扫描表
<a name="Scan"></a>

Amazon DynamoDB 中的 `Scan` 操作读取表或二级索引中的每个项目。默认情况下，`Scan` 操作返回表或索引中每个项目的全部数据属性。您可以使用 `ProjectionExpression` 参数，以便 `Scan` 仅返回部分属性而不是全部属性。

`Scan` 始终返回结果集。如果未找到匹配的项目，结果集将为空。

单个 `Scan` 请求最多可检索 1 MB 数据。（可选）DynamoDB 可以向这些数据应用筛选表达式，从而在将数据返回给用户之前缩小结果范围。

**Topics**
+ [扫描的筛选表达式](#Scan.FilterExpression)
+ [限制结果集中的项目数](#Scan.Limit)
+ [对结果分页](#Scan.Pagination)
+ [对结果中的项目进行计数](#Scan.Count)
+ [扫描占用的容量单位](#Scan.CapacityUnits)
+ [扫描的读取一致性](#Scan.ReadConsistency)
+ [并行扫描](#Scan.ParallelScan)

## 扫描的筛选表达式
<a name="Scan.FilterExpression"></a>

如果您需要进一步细化 `Scan` 结果，则可以选择性地提供筛选表达式。*筛选表达式*可确定 `Scan` 结果中应返回给您的项目。所有其他结果将会丢弃。

筛选表达式在 `Scan` 已完成但结果尚未返回时应用。因此，无论是否存在筛选表达式，`Scan` 都将占用同等数量的读取容量。

`Scan` 操作最多可检索 1 MB 的数据。此限制在计算筛选表达式之前应用。

使用 `Scan`，您可以在筛选表达式中指定任何属性，包括分区键和排序键属性。

筛选表达式的语法与条件表达式的相同。筛选表达式可使用的比较运算符、函数和逻辑运算符与条件表达式可使用的相同。有关逻辑运算符的更多信息，请参阅 [DynamoDB 中的条件表达式和筛选表达式、运算符及函数](Expressions.OperatorsAndFunctions.md)。

**Example**  
以下 AWS Command Line Interface (AWS CLI) 示例将扫描 `Thread` 表，此时仅返回此表中由特定用户最新发布到的项目。  

```
aws dynamodb scan \
     --table-name Thread \
     --filter-expression "LastPostedBy = :name" \
     --expression-attribute-values '{":name":{"S":"User A"}}'
```

## 限制结果集中的项目数
<a name="Scan.Limit"></a>

`Scan` 操作可让您限制结果中返回的项目数。为此，将 `Limit` 参数设置为您在筛选条件表达式求值前希望 `Scan` 操作返回的最大项目数。

例如，假设您对某个表进行 `Scan`，`Limit` 值为 `6`，并且没有筛选表达式。`Scan` 结果包含表中的前 6 个项目。

现在假设您向 `Scan` 添加了一个筛选表达式。在这种情况下，DynamoDB 将向返回的前 6 个项目应用筛选表达式，不考虑不匹配的项目。最终的 `Scan` 结果将包含 6 个或更少的项目，具体取决于筛选出的项目数。

## 对结果分页
<a name="Scan.Pagination"></a>

DynamoDB *分页*来自 `Scan` 操作的结果。利用分页，`Scan` 结果将分成若干“页”大小为 1 MB（或更小）的数据。应用程序可以先处理第一页结果，然后处理第二页结果，依此类推。

单次 `Scan` 只会返回符合 1 MB 大小限制的结果集。

要确定是否存在更多结果，并一次检索一页结果，应用程序应执行以下操作：

1. 检查低级别 `Scan` 结果：
   + 如果结果包含 `LastEvaluatedKey` 元素，请继续步骤 2。
   + 如果结果中*没有* `LastEvaluatedKey`，则表示没有其他要检索的项目。

1. 构造新的 `Scan` 请求，使用与前一个请求相同的参数。但是，此次获取来自步骤 1 的 `LastEvaluatedKey` 值，并将其用作新 `ExclusiveStartKey` 请求中的 `Scan` 参数。

1. 运行新的 `Scan` 请求。

1. 前往步骤 1。

换言之，`LastEvaluatedKey` 响应中的 `Scan` 应该用作下一 `ExclusiveStartKey` 请求的 `Scan`。如果 `LastEvaluatedKey` 响应中没有 `Scan` 元素，则表示您已检索最后一页结果。（检查是否没有 `LastEvaluatedKey` 是确定您是否已到达结果集末尾的唯一方式。）

您可以使用 AWS CLI 查看此行为。AWS CLI 向 DynamoDB 反复发送低级别 `Scan` 请求，直到请求中不再有 `LastEvaluatedKey`。请考虑以下 AWS CLI 示例，它扫描整个 `Movies` 表，但仅返回特定流派的电影。

```
aws dynamodb scan \
    --table-name Movies \
    --projection-expression "title" \
    --filter-expression 'contains(info.genres,:gen)' \
    --expression-attribute-values '{":gen":{"S":"Sci-Fi"}}' \
    --page-size 100  \
    --debug
```

通常，AWS CLI 自动处理分页。但是，在此例中，AWS CLI `--page-size` 参数限制了每页项目数。`--debug` 参数输出有关请求和响应的低级别信息。

**注意**  
根据您传递的输入参数，您的分页结果也会有所不同。  
使用 `aws dynamodb scan --table-name Prices --max-items 1` 返回 `NextToken`
使用 `aws dynamodb scan --table-name Prices --limit 1` 返回 `LastEvaluatedKey`。
另请注意，使用 `--starting-token` 特别要求 `NextToken` 值。

如果您运行该示例，DynamoDB 的首次响应类似如下内容。

```
2017-07-07 12:19:14,389 - MainThread - botocore.parsers - DEBUG - Response body:
b'{"Count":7,"Items":[{"title":{"S":"Monster on the Campus"}},{"title":{"S":"+1"}},
{"title":{"S":"100 Degrees Below Zero"}},{"title":{"S":"About Time"}},{"title":{"S":"After Earth"}},
{"title":{"S":"Age of Dinosaurs"}},{"title":{"S":"Cloudy with a Chance of Meatballs 2"}}],
"LastEvaluatedKey":{"year":{"N":"2013"},"title":{"S":"Curse of Chucky"}},"ScannedCount":100}'
```

响应中的 `LastEvaluatedKey` 指示并未检索所有项目。随后，AWS CLI 会将另一个 `Scan` 请求发送到 DynamoDB。此请求和响应模式继续，直到收到最终响应。

```
2017-07-07 12:19:17,830 - MainThread - botocore.parsers - DEBUG - Response body:
b'{"Count":1,"Items":[{"title":{"S":"WarGames"}}],"ScannedCount":6}'
```

如果不存在 `LastEvaluatedKey`，则表示没有其他要检索的项目。

**注意**  
AWS SDK 处理低级别的 DynamoDB 响应（包括是否存在 `LastEvaluatedKey`），并提供各种抽象概念对 `Scan` 结果进行分页。例如，适用于 Java 的 SDK 文档接口提供 `java.util.Iterator` 支持，以便您能够一次处理一个结果。  
对于各种编程语言的代码示例，请参阅本地化的 [Amazon DynamoDB 入门指南](https://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/)和 AWS SDK 文档。

## 对结果中的项目进行计数
<a name="Scan.Count"></a>

除了与您的条件匹配的项目之外，`Scan` 响应还包含以下元素：
+ `ScannedCount` — 在应用任何 `ScanFilter` 之前计算的项目数。`ScannedCount` 值很高但 `Count` 结果很少或为零，指 `Scan` 操作效率低下。如果您没有在请求中使用筛选器，则 `ScannedCount` 与 `Count` 相同。
+ `Count` — 在应用筛选表达式（如果有）*之后*，剩余的项目数量。

**注意**  
如果您不使用筛选表达式，那么 `ScannedCount` 和 `Count` 将具有相同的值。

如果 `Scan` 结果集的大小大于 1 MB，则 `ScannedCount` 和 `Count` 将仅表示项目总数的部分计数。您需要执行多次 `Scan` 操作才能检索所有结果（请参阅[对结果分页](#Scan.Pagination)）。

所有 `Scan` 响应都将包含由该特定 `ScannedCount` 请求处理的项目的 `Count` 和 `Scan`。要获取所有 `Scan` 请求的总和，您可以对 `ScannedCount` 和 `Count` 记录流水账。

## 扫描占用的容量单位
<a name="Scan.CapacityUnits"></a>

您可以对任何表或二级索引执行 `Scan` 操作。`Scan` 操作将占用读取容量单位，如下所示：


****  

| 如果对...进行 `Scan` | DynamoDB 将占用...的读取容量单位 | 
| --- | --- | 
| 表 | 表的预置读取容量。 | 
| 全局二级索引 | 索引的预置读取容量。 | 
| 本地二级索引 | 基表的预置读取容量。 | 

**注意**  
[基于资源的策略](access-control-resource-based.md)目前不支持跨账户访问二级索引扫描操作。

默认情况下，`Scan` 操作不会返回任何有关它占用的读取容量大小的数据。但是，您可在 `ReturnConsumedCapacity` 请求中指定 `Scan` 参数以获取此信息。下面是 `ReturnConsumedCapacity` 的有效设置：
+ `NONE` — 不返回任何已占用容量数据。（这是默认值。）
+ `TOTAL` — 响应包含占用的读取容量单位的总数。
+ `INDEXES` — 响应显示占用的读取容量单位的总数，以及访问的每个表和索引的占用容量。

DynamoDB 将基于项目数量以及这些项目的大小，而不是基于返回到应用程序的数据量来计算消耗的读取容量单位数。因此，无论您是请求所有属性（默认行为）还是只请求部分属性（使用投影表达式），占用的容量单位数都是相同的。无论您是否使用筛选表达式，该数值也都是一样的。`Scan` 消耗最小的读取容量单位，来为高达 4 KB 的项目每秒执行一次强一致性读取，或每秒执行两次最终一致性读取。如果您需要读取大于 4KB 的项目，DynamoDB 需要额外的读取请求单位。空表和分区键数量稀疏的超大表，可能会有在超出扫描的数据量后对一些额外的 RCU 收费的情况。这包括处理 `Scan` 请求的费用，即使不存在数据也是如此。

## 扫描的读取一致性
<a name="Scan.ReadConsistency"></a>

默认情况下，`Scan` 操作将执行最终一致性读取。这意味着 `Scan` 结果可能无法反映由最近完成的 `PutItem` 或 `UpdateItem` 操作导致的更改。有关更多信息，请参阅 [DynamoDB 读取一致性](HowItWorks.ReadConsistency.md)。

如果您需要强一致性读取，请在 `Scan` 开始时在 `ConsistentRead` 请求中将 `true` 参数设置为 `Scan`。这可确保在 `Scan` 开始前完成的所有写入操作都会包括在 `Scan` 响应中。

备份或复制表时，可以将 `ConsistentRead` 设置为 `true`，并结合 [DynamoDB Streams](./Streams.html)。首先，您使用 `Scan` 并将 `ConsistentRead` 设置为 true 来获取表中数据的一致性副本。`Scan` 操作期间，DynamoDB Streams 会记录表上发生的任何其他写入活动。在 `Scan` 完成后，您可以将流中的写入活动应用于该表。

**注意**  
与保留 `Scan` 的默认值 (`ConsistentRead`) 相比，`true` 设置为 `ConsistentRead` 的 `false` 操作将占用两倍的读取容量单位。

## 并行扫描
<a name="Scan.ParallelScan"></a>

默认情况下，`Scan` 操作按顺序处理数据。Amazon DynamoDB 以 1 MB 的增量向应用程序返回数据，应用程序执行其他 `Scan` 操作检索接下来 1 MB 的数据。

扫描的表或索引越大，`Scan` 完成需要的时间越长。此外，一个顺序 `Scan` 可能并不总是能够充分利用预调配的读取吞吐容量：即使 DynamoDB 跨多个物理分区分配大型表的数据，`Scan` 操作一次只能读取一个分区。出于这个原因，`Scan` 受到单个分区的最大吞吐量限制。

为了解决这些问题，`Scan`操作可以逻辑地将表或二级索引分成多个*分段*，多个应用程序工作进程并行扫描这些段。每个工作进程可以是一个线程（在支持多线程的编程语言中），也可以是一个操作系统进程。要执行并行扫描，每个工作进程都会发出自己的 `Scan` 请求，并使用以下参数：
+ `Segment`— 要由特定工作进程扫描的段。每个工作进程应使用不同的 `Segment` 值。
+ `TotalSegments`— 并行扫描的片段总数。该值必须与应用程序将使用的工作进程数量相同。

下图显示了多线程应用程序如何执行具有三度并行的并行 `Scan`。

![\[一种多线程应用程序，通过将表分为三个段来执行并行扫描。\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/images/ParallelScan.png)




在此图中，应用程序生成三个线程，并为每个线程分配一个编号。（段从零开始，因此第一个编号始终为 0。） 每个线程发出 `Scan` 请求，将 `Segment` 设置为其指定的编号并将 `TotalSegments` 设置为 3。每个线程扫描其指定的段，每次检索 1 MB 的数据，并将数据返回到应用程序的主线程。

DynamoDB 通过对每个项目的分区键应用哈希函数，将项目分配给*分段*。对于给定 `TotalSegments` 值，所有具有相同分区键的项目总是被分配给相同的 `Segment`。这意味着，在*项目 1*、*项目 2* 和*项目 3* 都共享 `pk="account#123"`（但排序键不同）的表中，无论排序键值或*项目集合*的大小如何，这些项目都将由同一个 worker 处理。

由于*分段*分配仅基于分区键哈希，因此分段的分布可能不均匀。有些分段可能不包含任何项目，而另一些分段可能包含许多带有大型项目集合的分区键。因此，增加分段总数并不能保证获得更快的扫描性能，尤其是在分区键在键空间中分布不均匀的情况下。

`Segment` 和 `TotalSegments` 值适用于单个 `Scan` 请求，可以随时使用不同的值。您可能需要对这些值以及您使用的工作集成数进行试验，直到您的应用程序达到最佳性能。

**注意**  
具有大量工作进程的并行扫描可以轻松占用正在扫描的表或索引的所有预配置吞吐量。如果表或索引也引起来自其他应用程序的大量读取或写入活动，最好避免进行此类扫描。  
要控制每个请求返回的数据量，请使用 `Limit` 参数。这有助于防止出现一个工作进程占用所有预配置吞吐量而牺牲所有其他工作进程的情况。

# PartiQL – 用于 Amazon DynamoDB 的 SQL 兼容语言
<a name="ql-reference"></a>

Amazon DynamoDB 支持 [PartiQL](https://partiql.org/)（一种 SQL 兼容查询语言），用于在 Amazon DynamoDB 中选择、插入、更新和删除数据。使用 PartiQL，您可以轻松地与 DynamoDB 表进行交互，并使用 AWS 管理控制台、NoSQL Workbench、AWS Command Line Interface 以及用于 PartiQL 的 DynamoDB API 运行临时查询。

PartiQL 操作提供与其他 DynamoDB 数据层面操作相同的可用性、延迟和性能。

以下部分介绍 PartiQL 的 DynamoDB 实现。

**Topics**
+ [什么是 PartiQL？](#ql-reference.what-is)
+ [Amazon DynamoDB 中的 PartiQL](#ql-reference.what-is)
+ [开始使用](ql-gettingstarted.md)
+ [数据类型](ql-reference.data-types.md)
+ [语句](ql-reference.statements.md)
+ [函数](ql-functions.md)
+ [运算符](ql-operators.md)
+ [事务](ql-reference.multiplestatements.transactions.md)
+ [分批操作](ql-reference.multiplestatements.batching.md)
+ [IAM 策略](ql-iam.md)

## 什么是 PartiQL？
<a name="ql-reference.what-is"></a>

*PartiQL* 在包含结构化数据、半结构化数据和嵌套数据的多个数据存储中提供 SQL 兼容的查询访问。它在 Amazon 中广泛使用，现在可作为许多 AWS 服务（包括 DynamoDB）的一部分提供。

有关 PartiQL 规范和核心查询语言的教程，请参阅 [ParameSQL 文档](https://partiql.org/docs.html)。

**注意**  
Amazon DynamoDB 支持 [PartiQL](https://partiql.org/) 查询语言的*子集*。
Amazon DynamoDB 不支持 [Amazon ion](http://amzn.github.io/ion-docs/) 数据格式或 Amazon ion 文字。

## Amazon DynamoDB 中的 PartiQL
<a name="ql-reference.what-is"></a>

要在 DynamoDB 中运行 PartiQL 查询，您可以使用：
+ DynamoDB 控制台
+ NoSQL Workbench
+ AWS Command Line Interface（AWS CLI）
+ DynamoDB API

有关使用这些方法访问 DynamoDB 的信息，请参阅[访问 DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AccessingDynamoDB.html)。

# PartiQL for DynamoDB 入门
<a name="ql-gettingstarted"></a>

本节介绍如何从 Amazon DynamoDB 控制台、AWS Command Line Interface (AWS CLI) 和 DynamoDB API 使用 PartiQL for DynamoDB。

在以下 DynamoDB 例中，[DynamoDB 入门](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStartedDynamoDB.html)教程中定义的 DynamoDB 表是一个前提条件。

有关使用 DynamoDB 控制台、AWS Command Line Interface 或 DynamoDB API 访问 DynamoDB 的信息，请参阅[访问 DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AccessingDynamoDB.html)。

要[下载](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.settingup.html)并使用 [NoSQL Workbench](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.html) 生成 [PartiQL for DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html) 语句，请选择 NoSQL Workbench for DynamoDB [操作生成器](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.querybuilder.operationbuilder.html)右上角的 **PartiQL operations**（PartiQL 操作）。

------
#### [ Console ]

![\[PartiQL 编辑器界面，显示对 Music 表运行查询操作的结果。\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/images/partiqlgettingstarted.png)


1. 登录 AWS 管理控制台，打开 DynamoDB 控制台：[https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)。

1. 在控制台左侧的导航窗格中，选择 **PartiQL editor (PartiQL 编辑器)**。

1. 选择 **Music** 表。

1. 选择 **Query table (查询表)**。此操作生成不会导致完整表扫描的查询。

1. 将 `partitionKeyValue` 替换为字符串值 `Acme Band`。将 `sortKeyValue` 替换为字符串值 `Happy Day`。

1. 选择 **Run (运行)** 按钮。

1. 选择 **Table view (表视图)** 或 **JSON view (JSON 视图)** 按钮，查看查询结果。

------
#### [ NoSQL workbench ]

![\[NoSQL Workbench 界面。它显示一条 PartiQL SELECT 语句，您可以对 Music 表运行该语句。\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/images/workbench/partiql.single.png)


1. 选择 **PartiQL statement (PartiQL 语句)**。

1. 输入以下 PartiQL [SELECT 语句](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.select.html) 

   ```
   SELECT *                                         
   FROM Music  
   WHERE Artist=? and SongTitle=?
   ```

1. 指定 `Artist` 和 `SongTitle` 参数值：

   1. 选择 **Optional request parameters (可选请求参数)**。

   1. 选择 **Add new parameters (添加新参数)**。

   1. 选择属性类型 **string** 和值 `Acme Band`。

   1. 重复步骤 b 和 c，然后选择类型 **string** 和值 `PartiQL Rocks`。

1. 如果要生成代码，请选择 **Generate code (生成代码)**。

   从显示的选项卡中选择所需的语言。现在，您便可复制此代码并在应用程序中使用它。

1. 如果要立即执行操作，请选择 **Run (执行)**。

------
#### [ AWS CLI ]

1. 使用 INSERT PartiQL 语句在 `Music` 表中创建项目。

   ```
   aws dynamodb execute-statement --statement "INSERT INTO Music  \
   					    VALUE  \
   					    {'Artist':'Acme Band','SongTitle':'PartiQL Rocks'}"
   ```

1. 使用 SELECT PartiQL 语句从 Music 表中检索项目。

   ```
   aws dynamodb execute-statement --statement "SELECT * FROM Music   \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

1. 使用 INSERT PartiQL 语句在 `Music` 表中更新项目。

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET AwardsWon=1  \
                                               SET AwardDetail={'Grammys':[2020, 2018]}  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   为 `Music` 表中的项目添加列表值。

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET AwardDetail.Grammys =list_append(AwardDetail.Grammys,[2016])  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   为 `Music` 表中的项目移除列表值。

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               REMOVE AwardDetail.Grammys[2]  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   为 `Music` 表中的项目添加映射成员。

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET AwardDetail.BillBoard=[2020]  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   为 `Music` 表中的项目添加新字符串集属性。

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET BandMembers =<<'member1', 'member2'>>  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   为 `Music` 表中的项目更新字符串集属性。

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET BandMembers =set_add(BandMembers, <<'newmember'>>)  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

1. 使用 DELETE PartiQL 语句从 `Music` 表删除项目。

   ```
   aws dynamodb execute-statement --statement "DELETE  FROM Music  \
       WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

------
#### [ Java ]

```
import java.util.ArrayList;
import java.util.List;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import software.amazon.dynamodb.AmazonDynamoDB;
import software.amazon.dynamodb.AmazonDynamoDBClientBuilder;
import software.amazon.dynamodb.model.AttributeValue;
import software.amazon.dynamodb.model.ConditionalCheckFailedException;
import software.amazon.dynamodb.model.ExecuteStatementRequest;
import software.amazon.dynamodb.model.ExecuteStatementResult;
import software.amazon.dynamodb.model.InternalServerErrorException;
import software.amazon.dynamodb.model.ItemCollectionSizeLimitExceededException;
import software.amazon.dynamodb.model.ProvisionedThroughputExceededException;
import software.amazon.dynamodb.model.RequestLimitExceededException;
import software.amazon.dynamodb.model.ResourceNotFoundException;
import software.amazon.dynamodb.model.TransactionConflictException;

public class DynamoDBPartiQGettingStarted {

    public static void main(String[] args) {
        // Create the DynamoDB Client with the region you want
        AmazonDynamoDB dynamoDB = createDynamoDbClient("us-west-1");

        try {
            // Create ExecuteStatementRequest
            ExecuteStatementRequest executeStatementRequest = new ExecuteStatementRequest();
            List<AttributeValue> parameters= getPartiQLParameters();

            //Create an item in the Music table using the INSERT PartiQL statement
            processResults(executeStatementRequest(dynamoDB, "INSERT INTO Music value {'Artist':?,'SongTitle':?}", parameters));

            //Retrieve an item from the Music table using the SELECT PartiQL statement.
            processResults(executeStatementRequest(dynamoDB, "SELECT * FROM Music  where Artist=? and SongTitle=?", parameters));

            //Update an item in the Music table using the UPDATE PartiQL statement.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET AwardsWon=1 SET AwardDetail={'Grammys':[2020, 2018]}  where Artist=? and SongTitle=?", parameters));

            //Add a list value for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET AwardDetail.Grammys =list_append(AwardDetail.Grammys,[2016])  where Artist=? and SongTitle=?", parameters));

            //Remove a list value for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music REMOVE AwardDetail.Grammys[2]   where Artist=? and SongTitle=?", parameters));

            //Add a new map member for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music set AwardDetail.BillBoard=[2020] where Artist=? and SongTitle=?", parameters));

            //Add a new string set attribute for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET BandMembers =<<'member1', 'member2'>> where Artist=? and SongTitle=?", parameters));

            //update a string set attribute for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET BandMembers =set_add(BandMembers, <<'newmember'>>) where Artist=? and SongTitle=?", parameters));

            //Retrieve an item from the Music table using the SELECT PartiQL statement.
            processResults(executeStatementRequest(dynamoDB, "SELECT * FROM Music  where Artist=? and SongTitle=?", parameters));

            //delete an item from the Music Table
            processResults(executeStatementRequest(dynamoDB, "DELETE  FROM Music  where Artist=? and SongTitle=?", parameters));
        } catch (Exception e) {
            handleExecuteStatementErrors(e);
        }
    }

    private static AmazonDynamoDB createDynamoDbClient(String region) {
        return AmazonDynamoDBClientBuilder.standard().withRegion(region).build();
    }

    private static List<AttributeValue> getPartiQLParameters() {
        List<AttributeValue> parameters = new ArrayList<AttributeValue>();
        parameters.add(new AttributeValue("Acme Band"));
        parameters.add(new AttributeValue("PartiQL Rocks"));
        return parameters;
    }

    private static ExecuteStatementResult executeStatementRequest(AmazonDynamoDB client, String statement, List<AttributeValue> parameters ) {
        ExecuteStatementRequest request = new ExecuteStatementRequest();
        request.setStatement(statement);
        request.setParameters(parameters);
        return client.executeStatement(request);
    }

    private static void processResults(ExecuteStatementResult executeStatementResult) {
        System.out.println("ExecuteStatement successful: "+ executeStatementResult.toString());

    }

    // Handles errors during ExecuteStatement execution. Use recommendations in error messages below to add error handling specific to
    // your application use-case.
    private static void handleExecuteStatementErrors(Exception exception) {
        try {
            throw exception;
        } catch (ConditionalCheckFailedException ccfe) {
            System.out.println("Condition check specified in the operation failed, review and update the condition " +
                                       "check before retrying. Error: " + ccfe.getErrorMessage());
        } catch (TransactionConflictException tce) {
            System.out.println("Operation was rejected because there is an ongoing transaction for the item, generally " +
                                       "safe to retry with exponential back-off. Error: " + tce.getErrorMessage());
        } catch (ItemCollectionSizeLimitExceededException icslee) {
            System.out.println("An item collection is too large, you\'re using Local Secondary Index and exceeded " +
                                       "size limit of items per partition key. Consider using Global Secondary Index instead. Error: " + icslee.getErrorMessage());
        } catch (Exception e) {
            handleCommonErrors(e);
        }
    }

    private static void handleCommonErrors(Exception exception) {
        try {
            throw exception;
        } catch (InternalServerErrorException isee) {
            System.out.println("Internal Server Error, generally safe to retry with exponential back-off. Error: " + isee.getErrorMessage());
        } catch (RequestLimitExceededException rlee) {
            System.out.println("Throughput exceeds the current throughput limit for your account, increase account level throughput before " +
                                       "retrying. Error: " + rlee.getErrorMessage());
        } catch (ProvisionedThroughputExceededException ptee) {
            System.out.println("Request rate is too high. If you're using a custom retry strategy make sure to retry with exponential back-off. " +
                                       "Otherwise consider reducing frequency of requests or increasing provisioned capacity for your table or secondary index. Error: " +
                                       ptee.getErrorMessage());
        } catch (ResourceNotFoundException rnfe) {
            System.out.println("One of the tables was not found, verify table exists before retrying. Error: " + rnfe.getErrorMessage());
        } catch (AmazonServiceException ase) {
            System.out.println("An AmazonServiceException occurred, indicates that the request was correctly transmitted to the DynamoDB " +
                                       "service, but for some reason, the service was not able to process it, and returned an error response instead. Investigate and " +
                                       "configure retry strategy. Error type: " + ase.getErrorType() + ". Error message: " + ase.getErrorMessage());
        } catch (AmazonClientException ace) {
            System.out.println("An AmazonClientException occurred, indicates that the client was unable to get a response from DynamoDB " +
                                       "service, or the client was unable to parse the response from the service. Investigate and configure retry strategy. "+
                                       "Error: " + ace.getMessage());
        } catch (Exception e) {
            System.out.println("An exception occurred, investigate and configure retry strategy. Error: " + e.getMessage());
        }
    }

}
```

------

## 使用参数化语句
<a name="ql-gettingstarted.parameterized"></a>

您可以使用问号（`?`）占位符并在 `Parameters` 字段中单独提供值，而不是将值直接嵌入到 PartiQL 语句字符串中。每个 `?` 值都按提供的顺序替换为相应的参数值。

使用参数化语句是一种最佳实践，因为这可以将语句结构与数据值分开，从而使语句更易于读懂和重复使用。这还可以避免在语句字符串中手动格式化和转义属性值的需求。

`ExecuteStatement`、`BatchExecuteStatement` 和 `ExecuteTransaction` 操作支持参数化语句。

以下示例使用分区键和排序键的参数化值从 `Music` 表中检索项目。

------
#### [ AWS CLI parameterized ]

```
aws dynamodb execute-statement \
    --statement "SELECT * FROM \"Music\" WHERE Artist=? AND SongTitle=?" \
    --parameters '[{"S": "Acme Band"}, {"S": "PartiQL Rocks"}]'
```

------
#### [ Java parameterized ]

```
List<AttributeValue> parameters = new ArrayList<>();
parameters.add(new AttributeValue("Acme Band"));
parameters.add(new AttributeValue("PartiQL Rocks"));

ExecuteStatementRequest request = new ExecuteStatementRequest()
    .withStatement("SELECT * FROM Music WHERE Artist=? AND SongTitle=?")
    .withParameters(parameters);

ExecuteStatementResult result = dynamoDB.executeStatement(request);
```

------
#### [ Python parameterized ]

```
response = dynamodb_client.execute_statement(
    Statement="SELECT * FROM Music WHERE Artist=? AND SongTitle=?",
    Parameters=[
        {'S': 'Acme Band'},
        {'S': 'PartiQL Rocks'}
    ]
)
```

------

**注意**  
前面入门部分中的 Java 示例自始至终都在使用参数化语句。`getPartiQLParameters()` 方法构建参数列表，每条语句都使用 `?` 占位符而不是内联值。

# DynamoDB 的 PartiQL 数据类型
<a name="ql-reference.data-types"></a>

下表列出可用于 PartiQL for DynamoDB 的数据类型。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/amazondynamodb/latest/developerguide/ql-reference.data-types.html)

## 示例
<a name="ql-reference.data-types"></a>

以下语句演示如何插入以下数据类型：`String`、`Number`、`Map`、`List`、`Number Set` 和 `String Set`。

```
INSERT INTO TypesTable value {'primarykey':'1', 
'NumberType':1,
'MapType' : {'entryname1': 'value', 'entryname2': 4}, 
'ListType': [1,'stringval'], 
'NumberSetType':<<1,34,32,4.5>>, 
'StringSetType':<<'stringval','stringval2'>>
}
```

以下语句演示了如何将新元素插入到 `Map`、`List`、`Number Set` 和 `String Set`类型并更改 `Number` 类型的值。

```
UPDATE TypesTable 
SET NumberType=NumberType + 100 
SET MapType.NewMapEntry=[2020, 'stringvalue', 2.4]
SET ListType = LIST_APPEND(ListType, [4, <<'string1', 'string2'>>])
SET NumberSetType= SET_ADD(NumberSetType, <<345, 48.4>>)
SET StringSetType = SET_ADD(StringSetType, <<'stringsetvalue1', 'stringsetvalue2'>>)
WHERE primarykey='1'
```

以下语句演示如何从 `Map`、`List`、`Number Set` 和 `String Set` 类型移除元素，并更改 `Number` 类型的值。

```
UPDATE TypesTable 
SET NumberType=NumberType - 1
REMOVE ListType[1]
REMOVE MapType.NewMapEntry
SET NumberSetType = SET_DELETE( NumberSetType, <<345>>)
SET StringSetType = SET_DELETE( StringSetType, <<'stringsetvalue1'>>)
WHERE primarykey='1'
```

有关更多信息，请参阅 [DynamoDB 数据类型](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes)。

# PartiQL for DynamoDB 语句
<a name="ql-reference.statements"></a>

Amazon DynamoDB 支持以下 PartiQL 语句。

**注意**  
DynamoDB 不支持所有 PartiQL 语句。  
此参考提供可以使用 AWS CLI 或 API 手动运行的 PartiQL 语句的基本语法和用法示例。

*数据操作语言* (DML) 是一组用于管理 DynamoDB 表中的数据的 PartiQL 语句。可以使用 DML 语句在表中添加、修改或删除数据。

支持以下 DML 和查询语言语句：
+ [PartiQL for DynamoDB 的 Select 语句](ql-reference.select.md)
+ [PartiQL for DynamoDB Update 语句](ql-reference.update.md)
+ [PartiQL for DynamoDB Insert 语句](ql-reference.insert.md)
+ [PartiQL for DynamoDB Delete 语句](ql-reference.delete.md)

PartiQL for DynamoDB 还支持 [使用 PartiQL for DynamoDB 执行事务](ql-reference.multiplestatements.transactions.md) 和 [对 PartiQL for DynamoDB 运行批处理操作](ql-reference.multiplestatements.batching.md)。

# PartiQL for DynamoDB 的 Select 语句
<a name="ql-reference.select"></a>

使用 `SELECT` 语句从 Amazon DynamoDB 的表检索数据。

如果 WHERE 子句中未提供带有分区键的相等或 IN 条件，使用 `SELECT` 语句会导致全表扫描。扫描操作会检查每个项目的请求值，并且可以在单个操作中使用大型表或索引的预置吞吐量。

如果您想避免在 PartiQL 中进行全表扫描，您可以：
+ 创作您的 `SELECT` 语句不会导致全表扫描，方法是确保您的 [WHERE 子句条件](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.select.html#ql-reference.select.parameters)相应地配置。
+ 使用《DynamoDB 开发人员指南》[示例：允许 Select 语句并拒绝 PartiQL for DynamoDB 的完整表扫描语句](ql-iam.md#access-policy-ql-iam-example6)中指定的 IAM 策略禁用全表扫描。

有关更多信息，请参阅《DynamoDB 开发人员指南》中的[查询和扫描数据的最佳实践](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-query-scan.html)。

**Topics**
+ [语法](#ql-reference.select.syntax)
+ [参数](#ql-reference.select.parameters)
+ [示例](#ql-reference.select.examples)

## 语法
<a name="ql-reference.select.syntax"></a>

```
SELECT expression  [, ...] 
FROM table[.index]
[ WHERE condition ] [ [ORDER BY key [DESC|ASC] , ...]
```

## 参数
<a name="ql-reference.select.parameters"></a>

***expression***  
（必需）从 `*` 通配符形成的投影，或者结果集的一个或多个属性名称或文档路径的投影列表。表达式可以包括对 [将 PartiQL 函数和 DynamoDB 结合使用](ql-functions.md) 或通过 [用于 DynamoDB 的 PartiQL 算术、比较和逻辑运算符](ql-operators.md) 修改的字段的调用。

***table***  
（必需）要查询的表名。

***index***  
（可选）要查询的索引的名称。  
查询索引时，必须在表名和索引名称中添加双引号。  

```
SELECT * 
FROM "TableName"."IndexName"
```

***条件***  
（可选）查询的选择条件。  
为了确保 `SELECT` 语句不会导致全表扫描，`WHERE` 子句条件必须指定分区键。使用相等或 IN 运算符。  
例如，如果 `Orders` 表有 `OrderID` 分区键和其他非键属性，包括 `Address`，则以下语句不会导致完整表扫描：  

```
SELECT * 
FROM "Orders" 
WHERE OrderID = 100

SELECT * 
FROM "Orders" 
WHERE OrderID = 100 and Address='some address'

SELECT * 
FROM "Orders" 
WHERE OrderID = 100 or OrderID = 200

SELECT * 
FROM "Orders" 
WHERE OrderID IN [100, 300, 234]
```
以下 `SELECT` 语句将导致完整表扫描：  

```
SELECT * 
FROM "Orders" 
WHERE OrderID > 1

SELECT * 
FROM "Orders" 
WHERE Address='some address'

SELECT * 
FROM "Orders" 
WHERE OrderID = 100 OR Address='some address'
```

***键***  
（可选）用于对返回结果进行排序的哈希键或排序键。默认顺序为升序 (`ASC`) 指定 `DESC` 如果您希望按降序重新调整结果。

**注意**  
如果省略 `WHERE` 子句，则检索表中的所有项目。

## 示例
<a name="ql-reference.select.examples"></a>

以下查询指定分区键 `OrderID`，并使用相等运算符，返回 `Orders` 表中的一个项目（如果存在）。

```
SELECT OrderID, Total
FROM "Orders"
WHERE OrderID = 1
```

以下查询使用 OR 运算符返回 `Orders` 表中具有特定分区键 `OrderID` 的所有项目。

```
SELECT OrderID, Total
FROM "Orders"
WHERE OrderID = 1 OR OrderID = 2
```

以下查询使用 IN 运算符返回 `Orders` 表中具有特定分区键 `OrderID` 的所有项目。返回的结果基于 `OrderID` 密钥属性值按降序排列。

```
SELECT OrderID, Total
FROM "Orders"
WHERE OrderID IN [1, 2, 3] ORDER BY OrderID DESC
```

以下查询显示一个全表扫描，返回 `Orders` 表中 `Total` 大于 500，`Total` 是非键属性的所有项目。

```
SELECT OrderID, Total 
FROM "Orders"
WHERE Total > 500
```

以下查询显示一个全表扫描，使用 IN 运算符和非键属性 `Total` 返回 `Orders` 表特定 `Total` 订单范围内的所有项目。

```
SELECT OrderID, Total 
FROM "Orders"
WHERE Total IN [500, 600]
```

以下查询显示一个全表扫描，使用 BETWEEN 运算符和非键属性 `Total` 返回 `Orders` 表特定 `Total` 订单范围内的所有项目。

```
SELECT OrderID, Total 
FROM "Orders" 
WHERE Total BETWEEN 500 AND 600
```

下面的查询在 WHERE 子句条件中指定分区键 `CustomerID` 和排序键 `MovieID`，在 SELECT 子句中使用完整文档路径，返回使用 firestick 设备观察的首个日期。

```
SELECT Devices.FireStick.DateWatched[0] 
FROM WatchList 
WHERE CustomerID= 'C1' AND MovieID= 'M1'
```

以下查询显示了一个完整表扫描，此扫描在 WHERE 子句条件中使用文档路径，返回 12/24/19 之后首次使用 firestick 设备的项目列表。

```
SELECT Devices 
FROM WatchList 
WHERE Devices.FireStick.DateWatched[0] >= '12/24/19'
```

# PartiQL for DynamoDB Update 语句
<a name="ql-reference.update"></a>

使用 `UPDATE` 语句来修改 Amazon DynamoDB 表中某个项目中一个或多个属性的值。

**注意**  
一次只能更新一个项目；不能发出单个 DynamoDB PartiQL 语句更新多个项目。有关更新多个项目的信息，请参阅 [使用 PartiQL for DynamoDB 执行事务](ql-reference.multiplestatements.transactions.md) 或 [对 PartiQL for DynamoDB 运行批处理操作](ql-reference.multiplestatements.batching.md)。

**Topics**
+ [语法](#ql-reference.update.syntax)
+ [参数](#ql-reference.update.parameters)
+ [返回值](#ql-reference.update.return)
+ [示例](#ql-reference.update.examples)

## 语法
<a name="ql-reference.update.syntax"></a>

```
UPDATE  table  
[SET | REMOVE]  path  [=  data] […]
WHERE condition [RETURNING returnvalues]
<returnvalues>  ::= [ALL OLD | MODIFIED OLD | ALL NEW | MODIFIED NEW] *
```

## 参数
<a name="ql-reference.update.parameters"></a>

***表*\$1**  
（必需）包含要修改的数据的表。

***path***  
（必需）要创建或修改的属性名称或文档路径。

***data***  
（必需）属性值或操作的结果。  
要与 SET 一起使用的支持操作：  
+ LIST\$1APPEND：向列表类型添加一个值。
+ SET\$1ADD：将值添加到数字或字符串集。
+ SET\$1DELETE：从数字或字符串集中删除值。

***条件***  
（必需）要修改的项目的选择条件。此条件必须解析为单个主键值。

***returnvalues***  
（可选）如果希望获取更新之前或之后显示的项目属性，使用 `returnvalues`。有效值为：  
+ `ALL OLD *` - 返回更新操作前项目的所有属性。
+ `MODIFIED OLD *` - 仅返回更新操作前已更新的属性。
+ `ALL NEW *` - 返回更新操作后显示的项目的所有属性。
+ `MODIFIED NEW *` - 仅返回 `UpdateItem` 操作后已更新的属性。

## 返回值
<a name="ql-reference.update.return"></a>

此语句不返回值，除非指定 `returnvalues` 参数。

**注意**  
如果对于 DynamoDB 表中的任何项目，UPDATE 语句的 WHERE 子句计算结果不为 true，则返回 `ConditionalCheckFailedException`。

## 示例
<a name="ql-reference.update.examples"></a>

更新现有项目的属性值。如果属性不存在，则创建该属性。

下面的查询添加一个 number 类型参数 (`AwardsWon`) 和一个 map 类型参数 (`AwardDetail`)，更新 `"Music"` 表的项目。

```
UPDATE "Music" 
SET AwardsWon=1 
SET AwardDetail={'Grammys':[2020, 2018]}  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

您可以添加 `RETURNING ALL OLD *` 以返回在 `Update` 操作之前显示的属性。

```
UPDATE "Music" 
SET AwardsWon=1 
SET AwardDetail={'Grammys':[2020, 2018]}  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
RETURNING ALL OLD *
```

这将返回以下内容：

```
{
    "Items": [
        {
            "Artist": {
                "S": "Acme Band"
            },
            "SongTitle": {
                "S": "PartiQL Rocks"
            }
        }
    ]
}
```

您可以添加 `RETURNING ALL NEW *` 以返回在 `Update` 操作之后显示的属性。

```
UPDATE "Music" 
SET AwardsWon=1 
SET AwardDetail={'Grammys':[2020, 2018]}  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
RETURNING ALL NEW *
```

这将返回以下内容：

```
{
    "Items": [
        {
            "AwardDetail": {
                "M": {
                    "Grammys": {
                        "L": [
                            {
                                "N": "2020"
                            },
                            {
                                "N": "2018"
                            }
                        ]
                    }
                }
            },
            "AwardsWon": {
                "N": "1"
            }
        }
    ]
}
```

以下查询通过附加到列表 `AwardDetail.Grammys`，更新 `"Music"` 表中的项目。

```
UPDATE "Music" 
SET AwardDetail.Grammys =list_append(AwardDetail.Grammys,[2016])  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

以下查询通过从列表 `AwardDetail.Grammys` 移除，更新 `"Music"` 表中的项目。

```
UPDATE "Music" 
REMOVE AwardDetail.Grammys[2]   
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

以下查询通过将 `BillBoard` 添加到映射 `AwardDetail`，更新 `"Music"` 表中的项目。

```
UPDATE "Music" 
SET AwardDetail.BillBoard=[2020] 
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

以下查询添加字符串集属性 `BandMembers`，更新 `"Music"` 表中的项目。

```
UPDATE "Music" 
SET BandMembers =<<'member1', 'member2'>> 
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

以下查询将 `newbandmember` 添加到字符串集 `BandMembers`，更新 `"Music"` 表中的项目。

```
UPDATE "Music" 
SET BandMembers =set_add(BandMembers, <<'newbandmember'>>) 
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

# PartiQL for DynamoDB Delete 语句
<a name="ql-reference.delete"></a>

使用 `DELETE` 语句从 Amazon DynamoDB 表中删除现有项目。

**注意**  
一次只能删除一个项目。不能发出单个 DynamoDB PartiQL 语句，删除多个项目。有关删除多个项目的信息，请参阅 [使用 PartiQL for DynamoDB 执行事务](ql-reference.multiplestatements.transactions.md) 或 [对 PartiQL for DynamoDB 运行批处理操作](ql-reference.multiplestatements.batching.md)。

**Topics**
+ [语法](#ql-reference.delete.syntax)
+ [参数](#ql-reference.delete.parameters)
+ [返回值](#ql-reference.delete.return)
+ [示例](#ql-reference.delete.examples)

## 语法
<a name="ql-reference.delete.syntax"></a>

```
DELETE FROM table 
 WHERE condition [RETURNING returnvalues]
 <returnvalues>  ::= ALL OLD *
```

## 参数
<a name="ql-reference.delete.parameters"></a>

***表*\$1**  
（必需）包含要删除的项目的 DynamoDB 表。

***条件***  
（必需）要删除的项目的选择条件；此条件必须解析为单个主键值。

***returnvalues***  
（可选）如果要获得删除前的项目属性，请使用 `returnvalues`。有效值为：  
+ `ALL OLD *` - 返回旧项目的内容。

## 返回值
<a name="ql-reference.delete.return"></a>

此语句不返回值，除非指定 `returnvalues` 参数。

**注意**  
如果 DynamoDB 表中没有任何与发出 DELETE 的项目的主键相同的项目，则返回 SUCCESS 并删除 0 个项目。如果表具有具有相同主键的项目，但 DELETE 语句的 WHERE 子句中的条件计算结果为 false，则返回 `ConditionalCheckFailedException`。

## 示例
<a name="ql-reference.delete.examples"></a>

以下查询删除 `"Music"` 表中的一个项目。

```
DELETE FROM "Music" WHERE "Artist" = 'Acme Band' AND "SongTitle" = 'PartiQL Rocks'
```

您可以添加参数 `RETURNING ALL OLD *` 以返回已删除的数据。

```
DELETE FROM "Music" WHERE "Artist" = 'Acme Band' AND "SongTitle" = 'PartiQL Rocks' RETURNING ALL OLD *
```

`Delete` 语句现在返回以下内容：

```
{
    "Items": [
        {
            "Artist": {
                "S": "Acme Band"
            },
            "SongTitle": {
                "S": "PartiQL Rocks"
            }
        }
    ]
}
```

# PartiQL for DynamoDB Insert 语句
<a name="ql-reference.insert"></a>

使用 `INSERT` 语句向 Amazon DynamoDB 的表添加项目。

**注意**  
一次只能插入一个项目；不能发出单个 DynamoDB PartiQL 语句插入多个项目。有关插入多个项目的信息，请参阅 [使用 PartiQL for DynamoDB 执行事务](ql-reference.multiplestatements.transactions.md) 或 [对 PartiQL for DynamoDB 运行批处理操作](ql-reference.multiplestatements.batching.md)。

**Topics**
+ [语法](#ql-reference.insert.syntax)
+ [参数](#ql-reference.insert.parameters)
+ [返回值](#ql-reference.insert.return)
+ [示例](#ql-reference.insert.examples)

## 语法
<a name="ql-reference.insert.syntax"></a>

插入单个项目。

```
INSERT INTO table VALUE item
```

## 参数
<a name="ql-reference.insert.parameters"></a>

***表*\$1**  
（必需）要在其中插入数据的表。表必须已经存在。

***item***  
（必需）表示为 [PartiQL tuple](https://partiql.org/docs.html) 的有效 DynamoDB 项目。您必须仅指定*一个*项目，项目中的每个属性名称都区分大小写，并且可以用*单*引号 (`'...'`) 在 PartiQL 中表示。  
字符串值也用*单*引号 (`'...'`) 在 PartiQL 中表示。

## 返回值
<a name="ql-reference.insert.return"></a>

此语句不返回任何值。

**注意**  
如果 DynamoDB 表中已具有与要插入项目的主键相同的项目，则返回 `DuplicateItemException`。

## 示例
<a name="ql-reference.insert.examples"></a>

```
INSERT INTO "Music" value {'Artist' : 'Acme Band','SongTitle' : 'PartiQL Rocks'}
```

# 将 PartiQL 函数和 DynamoDB 结合使用
<a name="ql-functions"></a>

Amazon DynamoDB 中的 PartiQL 支持以下 SQL 标准函数的内置版本。

**注意**  
DynamoDB 当前不支持任何未包含在此列表中的 SQL 函数。

## 聚合函数
<a name="ql-functions.aggregate"></a>
+ [将 SIZE 函数与 PartiQL for Amazon DynamoDB 结合使用](ql-functions.size.md)

## 条件函数
<a name="ql-functions.conditional"></a>
+ [将 EXISTS 函数与 PartiQL for DynamoDB 结合使用](ql-functions.exists.md)
+ [将 ATTRIBUTE\$1TYPE 函数与 PartiQL for DynamoDB 结合使用](ql-functions.attribute_type.md)
+ [将 BEGINS\$1WITH 函数与 PartiQL for DynamoDB 结合使用](ql-functions.beginswith.md)
+ [将 CONTAINS 函数与 PartiQL for DynamoDB 结合使用](ql-functions.contains.md)
+ [将 MISSING 函数与 PartiQL for DynamoDB 结合使用](ql-functions.missing.md)

# 将 EXISTS 函数与 PartiQL for DynamoDB 结合使用
<a name="ql-functions.exists"></a>

您可以使用 EXISTS 来执行与 [TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems) API 的 `ConditionCheck` 相同的功能。EXISTS 函数只能在事务中使用。

给定一个值，如果该值是非空集合则返回 `TRUE`。否则返回 `FALSE`。

**注意**  
此函数只能用于事务操作。

## 语法
<a name="ql-functions.exists.syntax"></a>

```
EXISTS ( statement )
```

## Arguments
<a name="ql-functions.exists.arguments"></a>

*语句*  
（必需）函数计算的 SELECT 语句。  
SELECT 语句必须指定完整主键和另一个条件。

## 返回类型
<a name="ql-functions.exists.return-type"></a>

`bool`

## 示例
<a name="ql-functions.exists.examples"></a>

```
EXISTS(
    SELECT * FROM "Music" 
    WHERE "Artist" = 'Acme Band' AND "SongTitle" = 'PartiQL Rocks')
```

# 将 BEGINS\$1WITH 函数与 PartiQL for DynamoDB 结合使用
<a name="ql-functions.beginswith"></a>

如果指定的属性以特定子字符串开头，则返回 `TRUE`。

## 语法
<a name="ql-functions.beginswith.syntax"></a>

```
begins_with(path, value )
```

## Arguments
<a name="ql-functions.beginswith.arguments"></a>

*path*  
（必需）要使用的属性名称或文档路径。

*值*  
（必需）要搜索的字符串。

## 返回类型
<a name="ql-functions.beginswith.return-type"></a>

`bool`

## 示例
<a name="ql-functions.beginswith.examples"></a>

```
SELECT * FROM "Orders" WHERE "OrderID"=1 AND begins_with("Address", '7834 24th')
```

# 将 MISSING 函数与 PartiQL for DynamoDB 结合使用
<a name="ql-functions.missing"></a>

如果项目不包含指定的属性，则返回 `TRUE`。此函数只能使用相等和不等运算符。

## 语法
<a name="ql-functions.missing.syntax"></a>

```
 attributename IS | IS NOT  MISSING 
```

## Arguments
<a name="ql-functions.missing.arguments"></a>

*attributename*  
（必需）要查找的属性名称。

## 返回类型
<a name="ql-functions.missing.return-type"></a>

`bool`

## 示例
<a name="ql-functions.missing.examples"></a>

```
SELECT * FROM Music WHERE "Awards" is MISSING
```

# 将 ATTRIBUTE\$1TYPE 函数与 PartiQL for DynamoDB 结合使用
<a name="ql-functions.attribute_type"></a>

如果指定路径中的属性为特定数据类型，则返回 `TRUE`。

## 语法
<a name="ql-functions.attribute_type.syntax"></a>

```
attribute_type( attributename, type )
```

## Arguments
<a name="ql-functions.attribute_type.arguments"></a>

*attributename*  
（必需）要使用的属性名称。

*类型*  
（必需）要检查的属性类型。有关有效值的列表，请参阅 DynamoDB [attribute\$1type](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions)。

## 返回类型
<a name="ql-functions.attribute_type.return-type"></a>

`bool`

## 示例
<a name="ql-functions.attribute_type.examples"></a>

```
SELECT * FROM "Music" WHERE attribute_type("Artist", 'S')
```

# 将 CONTAINS 函数与 PartiQL for DynamoDB 结合使用
<a name="ql-functions.contains"></a>

如果路径指定的属性为以下之一，则返回 `TRUE`：
+ 一个包含特定子字符串的字符串。
+ 一个包含集中某个特定元素的集合。

有关更多信息，请参阅 DynamoDB [contains](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) 函数。

## 语法
<a name="ql-functions.contains.syntax"></a>

```
contains( path, substring )
```

## Arguments
<a name="ql-functions.contains.arguments"></a>

*path*  
（必需）要使用的属性名称或文档路径。

*substring*  
（必需）要检查的属性子字符串或集合成员。有关更多信息，请参阅 DynamoDB [contains](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) 函数。

## 返回类型
<a name="ql-functions.contains.return-type"></a>

`bool`

## 示例
<a name="ql-functions.contains.examples"></a>

```
SELECT * FROM "Orders" WHERE "OrderID"=1 AND contains("Address", 'Kirkland')
```

# 将 SIZE 函数与 PartiQL for Amazon DynamoDB 结合使用
<a name="ql-functions.size"></a>

返回一个代表属性字节大小的数字。以下是与 size 结合使用的有效数据类型。有关更多信息，请参阅 DynamoDB [size](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) 函数。

## 语法
<a name="ql-functions.size.syntax"></a>

```
size( path)
```

## Arguments
<a name="ql-functions.size.arguments"></a>

*path*  
（必需）属性名称或文档路径。  
有关受支持的类型，请参阅 DynamoDB [size](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) 函数。

## 返回类型
<a name="ql-functions.size.return-type"></a>

`int`

## 示例
<a name="ql-functions.size.examples"></a>

```
 SELECT * FROM "Orders" WHERE "OrderID"=1 AND size("Image") >300
```

# 用于 DynamoDB 的 PartiQL 算术、比较和逻辑运算符
<a name="ql-operators"></a>

Amazon DynamoDB 中的 PartiQL 支持以下 [SQL 标准运算符](https://www.w3schools.com/sql/sql_operators.asp)。

**注意**  
DynamoDB 当前不支持任何未包含在此列表中的 SQL 运算符。

## 算术运算符
<a name="ql-operators.arithmetic"></a>


****  

| 运算符 | 说明 | 
| --- | --- | 
| \$1 | 添加 | 
| - | Subtract | 

## 比较运算符
<a name="ql-operators.comparison"></a>


****  

| 运算符 | 说明 | 
| --- | --- | 
| = | 等于 | 
| <> | 不等于 | 
| \$1= | 不等于 | 
| > | Greater than | 
| < | Less than | 
| >= | 大于或等于 | 
| <= | 小于或等于 | 

## 逻辑运算符
<a name="ql-operators.logical"></a>


****  

| 运算符 | 说明 | 
| --- | --- | 
| AND | 如果 AND 分隔的所有条件都为 TRUE，则为 TRUE | 
| BETWEEN |  如果操作数在比较范围内，则为 `TRUE`。 此运算符包括您对其应用的操作数的下限和上限。  | 
| IN | 如果操作数等于表达式列表的其中之一（最大 50 个哈希属性值或最大 100 个非键属性值），则为 `TRUE`。 结果分页返回，每页最多 10 个项目。如果 `IN` 列表包含更多值，则必须使用响应中返回的 `NextToken` 来检索后续页面。 | 
| IS | 如果运算数是给定 PartiQL 数据类型，包括 NULL 或 MISSING，则为 TRUE | 
| NOT | 反转给定布尔表达式的值 | 
| OR | 如果 OR 分隔的任意条件为 TRUE，则为 TRUE | 

有关使用逻辑运算符的更多信息，请参阅[进行比较](Expressions.OperatorsAndFunctions.md#Expressions.OperatorsAndFunctions.Comparators)和[逻辑评估](Expressions.OperatorsAndFunctions.md#Expressions.OperatorsAndFunctions.LogicalEvaluations)。

# 使用 PartiQL for DynamoDB 执行事务
<a name="ql-reference.multiplestatements.transactions"></a>

本部分介绍如何使用事务和 PartiQL for DynamoDB。PartiQL 事务限制为总共 100 条语句（操作）。

有关 DynamoDB 事务的更多信息，请参阅[使用 DynamoDB 事务管理复杂工作流](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transactions.html)。

**注意**  
整个事务必须由读取语句或写语句组成。您不能在一个事务中混合使用这两个语句。EXISTS 函数是一个例外。可用于检查项目的特定属性的条件，类似于 [TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems) API 操作中 `ConditionCheck` 的方式。

**Topics**
+ [语法](#ql-reference.multiplestatements.transactions.syntax)
+ [参数](#ql-reference.multiplestatements.transactions.parameters)
+ [返回值](#ql-reference.multiplestatements.transactions.return)
+ [示例](#ql-reference.multiplestatements.transactions.examples)

## 语法
<a name="ql-reference.multiplestatements.transactions.syntax"></a>

```
[
   {
      "Statement":" statement ",
      "Parameters":[
         {
            " parametertype " : " parametervalue "
         }, ...]
   } , ...
]
```

## 参数
<a name="ql-reference.multiplestatements.transactions.parameters"></a>

***语句***  
（必需）PartiQL for DynamoDB 支持的语句。  
整个事务必须由读取语句或写语句组成。您不能在一个事务中混合使用这两个语句。

***parametertype***  
（可选）DynamoDB 类型，如果在指定 PartiQL 语句时使用了参数。

***parametervalue***  
（可选）如果在指定 PartiQL 语句时使用了参数，则为参数值。

## 返回值
<a name="ql-reference.multiplestatements.transactions.return"></a>

此语句不会返回写入操作（INSERT、UPDATE 或 DELETE）的任何值。但是，根据 WHERE 子句中指定的条件，它会为读取操作 (SELECT) 返回不同的值。

**注意**  
如果任何单例 INSERT、UPDATE 或 DELETE 操作返回错误，则取消事务并抛出 `TransactionCanceledException` 异常，取消原因代码包括来自各个单例操作的错误。

## 示例
<a name="ql-reference.multiplestatements.transactions.examples"></a>

以下示例运行作为事务的多条语句。

------
#### [ AWS CLI ]

1. 将以下 JSON 代码保存到名为 partiql.json 的文件 

   ```
   [
       {
           "Statement": "EXISTS(SELECT * FROM \"Music\" where Artist='No One You Know' and SongTitle='Call Me Today' and Awards is  MISSING)"
       },
       {
           "Statement": "INSERT INTO Music value {'Artist':?,'SongTitle':'?'}",
           "Parameters": [{\"S\": \"Acme Band\"}, {\"S\": \"Best Song\"}]
       },
       {
           "Statement": "UPDATE \"Music\" SET AwardsWon=1 SET AwardDetail={'Grammys':[2020, 2018]}  where Artist='Acme Band' and SongTitle='PartiQL Rocks'"
       }
   ]
   ```

1. 在命令提示符中运行以下命令。

   ```
   aws dynamodb execute-transaction --transact-statements  file://partiql.json
   ```

------
#### [ Java ]

```
public class DynamoDBPartiqlTransaction {

    public static void main(String[] args) {
        // Create the DynamoDB Client with the region you want
        AmazonDynamoDB dynamoDB = createDynamoDbClient("us-west-2");
        
        try {
            // Create ExecuteTransactionRequest
            ExecuteTransactionRequest executeTransactionRequest = createExecuteTransactionRequest();
            ExecuteTransactionResult executeTransactionResult = dynamoDB.executeTransaction(executeTransactionRequest);
            System.out.println("ExecuteTransaction successful.");
            // Handle executeTransactionResult

        } catch (Exception e) {
            handleExecuteTransactionErrors(e);
        }
    }

    private static AmazonDynamoDB createDynamoDbClient(String region) {
        return AmazonDynamoDBClientBuilder.standard().withRegion(region).build();
    }

    private static ExecuteTransactionRequest createExecuteTransactionRequest() {
        ExecuteTransactionRequest request = new ExecuteTransactionRequest();
        
        // Create statements
        List<ParameterizedStatement> statements = getPartiQLTransactionStatements();

        request.setTransactStatements(statements);
        return request;
    }

    private static List<ParameterizedStatement> getPartiQLTransactionStatements() {
        List<ParameterizedStatement> statements = new ArrayList<ParameterizedStatement>();

        statements.add(new ParameterizedStatement()
                               .withStatement("EXISTS(SELECT * FROM "Music" where Artist='No One You Know' and SongTitle='Call Me Today' and Awards is  MISSING)"));

        statements.add(new ParameterizedStatement()
                               .withStatement("INSERT INTO "Music" value {'Artist':'?','SongTitle':'?'}")
                               .withParameters(new AttributeValue("Acme Band"),new AttributeValue("Best Song")));

        statements.add(new ParameterizedStatement()
                               .withStatement("UPDATE "Music" SET AwardsWon=1 SET AwardDetail={'Grammys':[2020, 2018]}  where Artist='Acme Band' and SongTitle='PartiQL Rocks'"));

        return statements;
    }

    // Handles errors during ExecuteTransaction execution. Use recommendations in error messages below to add error handling specific to 
    // your application use-case.
    private static void handleExecuteTransactionErrors(Exception exception) {
        try {
            throw exception;
        } catch (TransactionCanceledException tce) {
            System.out.println("Transaction Cancelled, implies a client issue, fix before retrying. Error: " + tce.getErrorMessage());
        } catch (TransactionInProgressException tipe) {
            System.out.println("The transaction with the given request token is already in progress, consider changing " +
                "retry strategy for this type of error. Error: " + tipe.getErrorMessage());
        } catch (IdempotentParameterMismatchException ipme) {
            System.out.println("Request rejected because it was retried with a different payload but with a request token that was already used, " +
                "change request token for this payload to be accepted. Error: " + ipme.getErrorMessage());
        } catch (Exception e) {
            handleCommonErrors(e);
        }
    }

    private static void handleCommonErrors(Exception exception) {
        try {
            throw exception;
        } catch (InternalServerErrorException isee) {
            System.out.println("Internal Server Error, generally safe to retry with exponential back-off. Error: " + isee.getErrorMessage());
        } catch (RequestLimitExceededException rlee) {
            System.out.println("Throughput exceeds the current throughput limit for your account, increase account level throughput before " + 
                "retrying. Error: " + rlee.getErrorMessage());
        } catch (ProvisionedThroughputExceededException ptee) {
            System.out.println("Request rate is too high. If you're using a custom retry strategy make sure to retry with exponential back-off. " +
                "Otherwise consider reducing frequency of requests or increasing provisioned capacity for your table or secondary index. Error: " + 
                ptee.getErrorMessage());
        } catch (ResourceNotFoundException rnfe) {
            System.out.println("One of the tables was not found, verify table exists before retrying. Error: " + rnfe.getErrorMessage());
        } catch (AmazonServiceException ase) {
            System.out.println("An AmazonServiceException occurred, indicates that the request was correctly transmitted to the DynamoDB " + 
                "service, but for some reason, the service was not able to process it, and returned an error response instead. Investigate and " +
                "configure retry strategy. Error type: " + ase.getErrorType() + ". Error message: " + ase.getErrorMessage());
        } catch (AmazonClientException ace) {
            System.out.println("An AmazonClientException occurred, indicates that the client was unable to get a response from DynamoDB " +
                "service, or the client was unable to parse the response from the service. Investigate and configure retry strategy. "+
                "Error: " + ace.getMessage());
        } catch (Exception e) {
            System.out.println("An exception occurred, investigate and configure retry strategy. Error: " + e.getMessage());
        }
    }

}
```

------

以下示例显示了 DynamoDB 读取具有 WHERE 子句中所指定不同条件的项目时的不同返回值。

------
#### [ AWS CLI ]

1. 将以下 JSON 代码保存到名为 partiql.json 的文件

   ```
   [
       // Item exists and projected attribute exists
       {
           "Statement": "SELECT * FROM "Music" WHERE Artist='No One You Know' and SongTitle='Call Me Today'"
       },
       // Item exists but projected attributes do not exist
       {
           "Statement": "SELECT non_existent_projected_attribute FROM "Music" WHERE Artist='No One You Know' and SongTitle='Call Me Today'"
       },
       // Item does not exist
       {
           "Statement": "SELECT * FROM "Music" WHERE Artist='No One I Know' and SongTitle='Call You Today'"
       }
   ]
   ```

1.  命令提示符中的以下命令。

   ```
   aws dynamodb execute-transaction --transact-statements  file://partiql.json
   ```

1. 如果成功，将返回以下响应。

   ```
   {
       "Responses": [
           // Item exists and projected attribute exists
           {
               "Item": {
                   "Artist":{
                       "S": "No One You Know"
                   },
                   "SongTitle":{
                       "S": "Call Me Today"
                   }    
               }
           },
           // Item exists but projected attributes do not exist
           {
               "Item": {}
           },
           // Item does not exist
           {}
       ]
   }
   ```

------

# 对 PartiQL for DynamoDB 运行批处理操作
<a name="ql-reference.multiplestatements.batching"></a>

本部分介绍如何使用处理器操作和 PartiQL for DynamoDB。

**注意**  
整个批处理必须由读取语句或写入语句组成；不能在一个批处理中混合使用这两种语句。
`BatchExecuteStatement` 和 `BatchWriteItem` 每批可执行的语句不超过 25 个。
`BatchExecuteStatement` 利用 `BatchGetItem`，后者在单独的语句中获取主键的列表。

**Topics**
+ [语法](#ql-reference.multiplestatements.batching.syntax)
+ [参数](#ql-reference.multiplestatements.batching.parameters)
+ [示例](#ql-reference.multiplestatements.batching.examples)

## 语法
<a name="ql-reference.multiplestatements.batching.syntax"></a>

```
[
  {
    "Statement": "SELECT pk FROM ProblemSet WHERE pk = 'p#9StkWHYTxm7x2AqSXcrfu7' AND sk = 'info'"
  },
  {
    "Statement": "SELECT pk FROM ProblemSet WHERE pk = 'p#isC2ChceGbxHgESc4szoTE' AND sk = 'info'"
  }
]
```

```
[
   {
      "Statement":" statement ",
      "Parameters":[
         {
            " parametertype " : " parametervalue "
         }, ...]
   } , ...
]
```

## 参数
<a name="ql-reference.multiplestatements.batching.parameters"></a>

***语句***  
（必需）PartiQL for DynamoDB 支持的语句。  
+ 整个批处理必须由读取语句或写入语句组成；不能在一个批处理中混合使用这两种语句。
+ `BatchExecuteStatement` 和 `BatchWriteItem` 每批可执行的语句不超过 25 个。

***parametertype***  
（可选）DynamoDB 类型，如果在指定 PartiQL 语句时使用了参数。

***parametervalue***  
（可选）如果在指定 PartiQL 语句时使用了参数，则为参数值。

## 示例
<a name="ql-reference.multiplestatements.batching.examples"></a>

------
#### [ AWS CLI ]

1. 将以下 json 保存到一个名为 partiql.json 的文件

   ```
   [
      {
   	 "Statement": "INSERT INTO Music VALUE {'Artist':?,'SongTitle':?}",
   	  "Parameters": [{"S": "Acme Band"}, {"S": "Best Song"}]
   	},
   	{
   	 "Statement": "UPDATE Music SET AwardsWon=1, AwardDetail={'Grammys':[2020, 2018]} WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
       }
   ]
   ```

1. 在命令提示符中运行以下命令。

   ```
   aws dynamodb batch-execute-statement  --statements  file://partiql.json
   ```

------
#### [ Java ]

```
public class DynamoDBPartiqlBatch {

    public static void main(String[] args) {
        // Create the DynamoDB Client with the region you want
        AmazonDynamoDB dynamoDB = createDynamoDbClient("us-west-2");
        
        try {
            // Create BatchExecuteStatementRequest
            BatchExecuteStatementRequest batchExecuteStatementRequest = createBatchExecuteStatementRequest();
            BatchExecuteStatementResult batchExecuteStatementResult = dynamoDB.batchExecuteStatement(batchExecuteStatementRequest);
            System.out.println("BatchExecuteStatement successful.");
            // Handle batchExecuteStatementResult

        } catch (Exception e) {
            handleBatchExecuteStatementErrors(e);
        }
    }

    private static AmazonDynamoDB createDynamoDbClient(String region) {

        return AmazonDynamoDBClientBuilder.standard().withRegion(region).build();
    }

    private static BatchExecuteStatementRequest createBatchExecuteStatementRequest() {
        BatchExecuteStatementRequest request = new BatchExecuteStatementRequest();

        // Create statements
        List<BatchStatementRequest> statements = getPartiQLBatchStatements();

        request.setStatements(statements);
        return request;
    }

    private static List<BatchStatementRequest> getPartiQLBatchStatements() {
        List<BatchStatementRequest> statements = new ArrayList<BatchStatementRequest>();

        statements.add(new BatchStatementRequest()
                               .withStatement("INSERT INTO Music value {'Artist':'Acme Band','SongTitle':'PartiQL Rocks'}"));

        statements.add(new BatchStatementRequest()
                               .withStatement("UPDATE Music set AwardDetail.BillBoard=[2020] where Artist='Acme Band' and SongTitle='PartiQL Rocks'"));

        return statements;
    }

    // Handles errors during BatchExecuteStatement execution. Use recommendations in error messages below to add error handling specific to 
    // your application use-case.
    private static void handleBatchExecuteStatementErrors(Exception exception) {
        try {
            throw exception;
        } catch (Exception e) {
            // There are no API specific errors to handle for BatchExecuteStatement, common DynamoDB API errors are handled below
            handleCommonErrors(e);
        }
    }

    private static void handleCommonErrors(Exception exception) {
        try {
            throw exception;
        } catch (InternalServerErrorException isee) {
            System.out.println("Internal Server Error, generally safe to retry with exponential back-off. Error: " + isee.getErrorMessage());
        } catch (RequestLimitExceededException rlee) {
            System.out.println("Throughput exceeds the current throughput limit for your account, increase account level throughput before " + 
                "retrying. Error: " + rlee.getErrorMessage());
        } catch (ProvisionedThroughputExceededException ptee) {
            System.out.println("Request rate is too high. If you're using a custom retry strategy make sure to retry with exponential back-off. " +
                "Otherwise consider reducing frequency of requests or increasing provisioned capacity for your table or secondary index. Error: " + 
                ptee.getErrorMessage());
        } catch (ResourceNotFoundException rnfe) {
            System.out.println("One of the tables was not found, verify table exists before retrying. Error: " + rnfe.getErrorMessage());
        } catch (AmazonServiceException ase) {
            System.out.println("An AmazonServiceException occurred, indicates that the request was correctly transmitted to the DynamoDB " + 
                "service, but for some reason, the service was not able to process it, and returned an error response instead. Investigate and " +
                "configure retry strategy. Error type: " + ase.getErrorType() + ". Error message: " + ase.getErrorMessage());
        } catch (AmazonClientException ace) {
            System.out.println("An AmazonClientException occurred, indicates that the client was unable to get a response from DynamoDB " +
                "service, or the client was unable to parse the response from the service. Investigate and configure retry strategy. "+
                "Error: " + ace.getMessage());
        } catch (Exception e) {
            System.out.println("An exception occurred, investigate and configure retry strategy. Error: " + e.getMessage());
        }
    }

}
```

------

# 将 IAM 安全策略与 PartiQL for DynamoDB 结合使用
<a name="ql-iam"></a>

需要以下权限：
+ 若要使用 PartiQL for DynamoDB 读取项目，您必须具有表或索引的 `dynamodb:PartiQLSelect` 权限。
+ 若要使用 PartiQL for DynamoDB 插入项目，您必须具有表或索引的 `dynamodb:PartiQLInsert` 权限。
+ 若要使用 PartiQL for DynamoDB 更新项目，您必须具有表或索引的 `dynamodb:PartiQLUpdate` 权限。
+ 若要使用 PartiQL for DynamoDB 删除项目，您必须具有表或索引的 `dynamodb:PartiQLDelete` 权限。

## 示例：允许表上所有 PartiQL for DynamoDB 语句 (Select/Insert/Update/Delete)
<a name="access-policy-ql-iam-example1"></a>

下面的 IAM policy 授予对表运行所有 PartiQL for DynamoDB 语句的权限。

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLInsert",
            "dynamodb:PartiQLUpdate",
            "dynamodb:PartiQLDelete",
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ]
      }
   ]
}
```

------

## 示例：允许表上的 PartiQL for DynamoDB select 语句
<a name="access-policy-ql-iam-example2"></a>

下面的 IAM policy 授予在特定表运行 `select` 语句的权限。

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ]
      }
   ]
}
```

------

## 示例：允许在索引上运行 PartiQL for DynamoDB insert 语句
<a name="access-policy-ql-iam-example3"></a>

下面的 IAM policy 授予在特定索引运行 `insert` 语句的权限。

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLInsert"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music/index/index1"
         ]
      }
   ]
}
```

------

## 示例：仅允许表上运行 PartiQL for DynamoDB 语句
<a name="access-policy-ql-iam-example4"></a>

下面的 IAM policy 授予在特定表运行事务语句的权限。

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLInsert",
            "dynamodb:PartiQLUpdate",
            "dynamodb:PartiQLDelete",
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ],
         "Condition":{
            "StringEquals":{
               "dynamodb:EnclosingOperation":[
                  "ExecuteTransaction"
               ]
            }
         }
      }
   ]
}
```

------

## 示例：允许运行 PartiQL for DynamoDB 非事务性读取和写入，阻止表上的 PartiQL 事务性读取和写入事务性语句。
<a name="access-policy-ql-iam-example5"></a>

 下面的 IAM policy 授予运行 PartiQL for DynamoDB 非事务性读取和写入的权限，同时阻止 PartiQL for DynamoDB 事务性读取和写入。

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Deny",
         "Action":[
            "dynamodb:PartiQLInsert",
            "dynamodb:PartiQLUpdate",
            "dynamodb:PartiQLDelete",
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ],
         "Condition":{
            "StringEquals":{
               "dynamodb:EnclosingOperation":[
                  "ExecuteTransaction"
               ]
            }
         }
      },
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLInsert",
            "dynamodb:PartiQLUpdate",
            "dynamodb:PartiQLDelete",
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ]
      }
   ]
}
```

------

## 示例：允许 Select 语句并拒绝 PartiQL for DynamoDB 的完整表扫描语句
<a name="access-policy-ql-iam-example6"></a>

下面的 IAM policy 授予在特定表运行 `select` 语句的权限，同时阻止会导致完整表扫描的 `select` 语句。

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Deny",
         "Action":[
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/WatchList"
         ],
         "Condition":{
            "Bool":{
               "dynamodb:FullTableScan":[
                  "true"
               ]
            }
         }
      },
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/WatchList"
         ]
      }
   ]
}
```

------

# 处理项目：Java
<a name="JavaDocumentAPIItemCRUD"></a>

您可以使用 适用于 Java 的 AWS SDK 文档 API 对某个表中的 Amazon DynamoDB 项目执行典型的创建、读取、更新和删除 (CRUD) 操作。

**注意**  
还提供一个对象持久化模型，可用来将客户端类映射到 DynamoDB 表。该方法可以减少需要编写的代码数量。有关更多信息，请参阅 [Java 1.x：DynamoDBMapper](DynamoDBMapper.md)。

此部分包含执行多个 Java 文档 API 项目操作的 Java 示例和多个可完全工作的示例。

**Topics**
+ [放置项目](#PutDocumentAPIJava)
+ [获取项目](#JavaDocumentAPIGetItem)
+ [批处理写入：放置和删除多个项目](#BatchWriteDocumentAPIJava)
+ [批处理获取：获取多个项目](#JavaDocumentAPIBatchGetItem)
+ [更新项目](#JavaDocumentAPIItemUpdate)
+ [删除项目](#DeleteMidLevelJava)
+ [示例：使用 适用于 Java 的 AWS SDK 文档 API 的 CRUD 操作](JavaDocumentAPICRUDExample.md)
+ [示例：使用 适用于 Java 的 AWS SDK 文档 API 的批处理操作](batch-operation-document-api-java.md)
+ [示例：使用 适用于 Java 的 AWS SDK 文档 API 处理二进制类型属性](JavaDocumentAPIBinaryTypeExample.md)

## 放置项目
<a name="PutDocumentAPIJava"></a>

`putItem` 方法能将项目存储在表中。如果项目已存在，则会替换整个项目。如果您不想替换整个项目，而只希望更新特定属性，那么您可以使用 `updateItem` 方法。有关更多信息，请参阅 [更新项目](#JavaDocumentAPIItemUpdate)。

------
#### [ Java v2 ]

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.PutItemResponse;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import java.util.HashMap;

/**
 * Before running this Java V2 code example, set up your development
 * environment, including your credentials.
 *
 * For more information, see the following documentation topic:
 *
 * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
 *
 * To place items into an Amazon DynamoDB table using the AWS SDK for Java V2,
 * its better practice to use the
 * Enhanced Client. See the EnhancedPutItem example.
 */
public class PutItem {
    public static void main(String[] args) {
        final String usage = """

                Usage:
                    <tableName> <key> <keyVal> <albumtitle> <albumtitleval> <awards> <awardsval> <Songtitle> <songtitleval>

                Where:
                    tableName - The Amazon DynamoDB table in which an item is placed (for example, Music3).
                    key - The key used in the Amazon DynamoDB table (for example, Artist).
                    keyval - The key value that represents the item to get (for example, Famous Band).
                    albumTitle - The Album title (for example, AlbumTitle).
                    AlbumTitleValue - The name of the album (for example, Songs About Life ).
                    Awards - The awards column (for example, Awards).
                    AwardVal - The value of the awards (for example, 10).
                    SongTitle - The song title (for example, SongTitle).
                    SongTitleVal - The value of the song title (for example, Happy Day).
                **Warning** This program will  place an item that you specify into a table!
                """;

        if (args.length != 9) {
            System.out.println(usage);
            System.exit(1);
        }

        String tableName = args[0];
        String key = args[1];
        String keyVal = args[2];
        String albumTitle = args[3];
        String albumTitleValue = args[4];
        String awards = args[5];
        String awardVal = args[6];
        String songTitle = args[7];
        String songTitleVal = args[8];

        Region region = Region.US_EAST_1;
        DynamoDbClient ddb = DynamoDbClient.builder()
                .region(region)
                .build();

        putItemInTable(ddb, tableName, key, keyVal, albumTitle, albumTitleValue, awards, awardVal, songTitle,
                songTitleVal);
        System.out.println("Done!");
        ddb.close();
    }

    public static void putItemInTable(DynamoDbClient ddb,
            String tableName,
            String key,
            String keyVal,
            String albumTitle,
            String albumTitleValue,
            String awards,
            String awardVal,
            String songTitle,
            String songTitleVal) {

        HashMap<String, AttributeValue> itemValues = new HashMap<>();
        itemValues.put(key, AttributeValue.builder().s(keyVal).build());
        itemValues.put(songTitle, AttributeValue.builder().s(songTitleVal).build());
        itemValues.put(albumTitle, AttributeValue.builder().s(albumTitleValue).build());
        itemValues.put(awards, AttributeValue.builder().s(awardVal).build());

        PutItemRequest request = PutItemRequest.builder()
                .tableName(tableName)
                .item(itemValues)
                .build();

        try {
            PutItemResponse response = ddb.putItem(request);
            System.out.println(tableName + " was successfully updated. The request id is "
                    + response.responseMetadata().requestId());

        } catch (ResourceNotFoundException e) {
            System.err.format("Error: The Amazon DynamoDB table \"%s\" can't be found.\n", tableName);
            System.err.println("Be sure that it exists and that you've typed its name correctly!");
            System.exit(1);
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }
}
```

------
#### [ Java v1 ]

按照以下步骤进行操作：

1. 创建 `DynamoDB` 类的实例。

1. 创建 `Table` 类的实例来代表要处理的表。

1. 创建 `Item` 类的实例来代表新项目。必须指定新项目的主键及其属性。

1. 使用您在之前步骤中创建的 `putItem`，调用 `Table` 对象的 `Item` 方法。

以下 Java 代码示例演示了上述任务。代码将新项目写入 `ProductCatalog` 表。

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

// Build a list of related items
List<Number> relatedItems = new ArrayList<Number>();
relatedItems.add(341);
relatedItems.add(472);
relatedItems.add(649);

//Build a map of product pictures
Map<String, String> pictures = new HashMap<String, String>();
pictures.put("FrontView", "http://example.com/products/123_front.jpg");
pictures.put("RearView", "http://example.com/products/123_rear.jpg");
pictures.put("SideView", "http://example.com/products/123_left_side.jpg");

//Build a map of product reviews
Map<String, List<String>> reviews = new HashMap<String, List<String>>();

List<String> fiveStarReviews = new ArrayList<String>();
fiveStarReviews.add("Excellent! Can't recommend it highly enough!  Buy it!");
fiveStarReviews.add("Do yourself a favor and buy this");
reviews.put("FiveStar", fiveStarReviews);

List<String> oneStarReviews = new ArrayList<String>();
oneStarReviews.add("Terrible product!  Do not buy this.");
reviews.put("OneStar", oneStarReviews);

// Build the item
Item item = new Item()
    .withPrimaryKey("Id", 123)
    .withString("Title", "Bicycle 123")
    .withString("Description", "123 description")
    .withString("BicycleType", "Hybrid")
    .withString("Brand", "Brand-Company C")
    .withNumber("Price", 500)
    .withStringSet("Color",  new HashSet<String>(Arrays.asList("Red", "Black")))
    .withString("ProductCategory", "Bicycle")
    .withBoolean("InStock", true)
    .withNull("QuantityOnHand")
    .withList("RelatedItems", relatedItems)
    .withMap("Pictures", pictures)
    .withMap("Reviews", reviews);

// Write the item to the table
PutItemOutcome outcome = table.putItem(item);
```

在上述示例中，项目具有标量（`String`、`Number`、`Boolean`、`Null`）、集 (`String Set`) 和文档类型（`List`、`Map`）的属性。

------

### 指定可选参数
<a name="PutItemJavaDocumentAPIOptions"></a>

除了必需的参数之外，您还可以为 `putItem` 方法指定可选参数。例如，以下 Java 代码示例使用可选参数指定上传项目的条件。如果未满足指定条件，那么 适用于 Java 的 AWS SDK 会抛出 `ConditionalCheckFailedException`。该代码示例在 `putItem` 方法中指定了以下可选参数：
+ 定义请求条件的 `ConditionExpression`。该代码定义了一个条件，仅在具有同一主键的现有项目包含与特定值相等的 ISBN 属性时，才替换该项目。
+ 将在条件中使用的 `ExpressionAttributeValues` 的映射。在这种情况下，只需要一个替换：条件表达式中的占位符 `:val` 在运行时被替换为要检查的实际 ISBN 值。

以下示例使用这些可选参数添加一个新的图书项目。

**Example**  

```
Item item = new Item()
    .withPrimaryKey("Id", 104)
    .withString("Title", "Book 104 Title")
    .withString("ISBN", "444-4444444444")
    .withNumber("Price", 20)
    .withStringSet("Authors",
        new HashSet<String>(Arrays.asList("Author1", "Author2")));

Map<String, Object> expressionAttributeValues = new HashMap<String, Object>();
expressionAttributeValues.put(":val", "444-4444444444");

PutItemOutcome outcome = table.putItem(
    item,
    "ISBN = :val", // ConditionExpression parameter
    null,          // ExpressionAttributeNames parameter - we're not using it for this example
    expressionAttributeValues);
```

### PutItem 和 JSON 文档
<a name="PutItemJavaDocumentAPI.JSON"></a>

您可以将 JSON 文档作为属性存储在 DynamoDB 表中。为此，请使用 `withJSON` 的 `Item` 方法。此方法会解析 JSON 文档并将每个元素映射到本地 DynamoDB 数据类型。

假设您想要存储以下 JSON 文档，其中包含可履行特定产品订单的供应商。

**Example**  

```
{
    "V01": {
        "Name": "Acme Books",
        "Offices": [ "Seattle" ]
    },
    "V02": {
        "Name": "New Publishers, Inc.",
        "Offices": ["London", "New York"
        ]
    },
    "V03": {
        "Name": "Better Buy Books",
        "Offices": [ "Tokyo", "Los Angeles", "Sydney"
        ]
    }
}
```

您可以使用 `withJSON` 方法，将此项目存储在 `ProductCatalog` 表的名为 `Map` 的 `VendorInfo` 属性中。以下 Java 代码示例演示了如何执行此操作。

```
// Convert the document into a String.  Must escape all double-quotes.
String vendorDocument = "{"
    + "    \"V01\": {"
    + "        \"Name\": \"Acme Books\","
    + "        \"Offices\": [ \"Seattle\" ]"
    + "    },"
    + "    \"V02\": {"
    + "        \"Name\": \"New Publishers, Inc.\","
    + "        \"Offices\": [ \"London\", \"New York\"" + "]" + "},"
    + "    \"V03\": {"
    + "        \"Name\": \"Better Buy Books\","
    +          "\"Offices\": [ \"Tokyo\", \"Los Angeles\", \"Sydney\""
    + "            ]"
    + "        }"
    + "    }";

Item item = new Item()
    .withPrimaryKey("Id", 210)
    .withString("Title", "Book 210 Title")
    .withString("ISBN", "210-2102102102")
    .withNumber("Price", 30)
    .withJSON("VendorInfo", vendorDocument);

PutItemOutcome outcome = table.putItem(item);
```

## 获取项目
<a name="JavaDocumentAPIGetItem"></a>

要检索单个项目，可以使用 `getItem` 对象的 `Table` 方法。按照以下步骤进行操作：

1. 创建 `DynamoDB` 类的实例。

1. 创建 `Table` 类的实例来代表要处理的表。

1. 调用 `getItem` 实例的 `Table` 方法。您必须指定要检索的项目的主键。

以下 Java 代码示例演示了上述步骤。该代码获取具有指定分区键的项目。

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

Item item = table.getItem("Id", 210);
```

### 指定可选参数
<a name="GetItemJavaDocumentAPIOptions"></a>

除了必需的参数之外，您还可以为 `getItem` 方法指定可选参数。例如，以下 Java 代码示例使用可选方法仅检索属性的特定列表，并指定强一致性读取。(要了解有关读取一致性的更多信息，请参阅 [DynamoDB 读取一致性](HowItWorks.ReadConsistency.md)。)

您可以使用 `ProjectionExpression` 只检索特定属性或元素，而不是整个项目。`ProjectionExpression` 可以使用文档路径指定顶级或嵌套属性。有关更多信息，请参阅 [在 DynamoDB 中使用投影表达式](Expressions.ProjectionExpressions.md)。

`getItem` 方法的参数不让您指定读取一致性。但是，您可以创建 `GetItemSpec`，这会将对所有输入的完整访问权限提供给低级 `GetItem` 操作。下面的代码示例创建 `GetItemSpec`，并且使用该规范作为 `getItem` 方法的输入。

**Example**  

```
GetItemSpec spec = new GetItemSpec()
    .withPrimaryKey("Id", 206)
    .withProjectionExpression("Id, Title, RelatedItems[0], Reviews.FiveStar")
    .withConsistentRead(true);

Item item = table.getItem(spec);

System.out.println(item.toJSONPretty());
```

 要以人类可读格式输出 `Item`，请使用 `toJSONPretty` 方法。上一例中的输出类似于下文所示。

```
{
  "RelatedItems" : [ 341 ],
  "Reviews" : {
    "FiveStar" : [ "Excellent! Can't recommend it highly enough! Buy it!", "Do yourself a favor and buy this" ]
  },
  "Id" : 123,
  "Title" : "20-Bicycle 123"
}
```

### GetItem 和 JSON 文档
<a name="GetItemJavaDocumentAPI.JSON"></a>

在 [PutItem 和 JSON 文档](#PutItemJavaDocumentAPI.JSON) 部分中，您在名为 `Map` 的 `VendorInfo` 属性中存储了一个 JSON 文档。您可以使用 `getItem` 方法检索 JSON 格式的整个文档。或者，您可以使用文档路径表示来仅检索文档中的部分元素。以下 Java 代码示例演示了这些技术。

```
GetItemSpec spec = new GetItemSpec()
    .withPrimaryKey("Id", 210);

System.out.println("All vendor info:");
spec.withProjectionExpression("VendorInfo");
System.out.println(table.getItem(spec).toJSON());

System.out.println("A single vendor:");
spec.withProjectionExpression("VendorInfo.V03");
System.out.println(table.getItem(spec).toJSON());

System.out.println("First office location for this vendor:");
spec.withProjectionExpression("VendorInfo.V03.Offices[0]");
System.out.println(table.getItem(spec).toJSON());
```

上一例中的输出类似于下文所示。

```
All vendor info:
{"VendorInfo":{"V03":{"Name":"Better Buy Books","Offices":["Tokyo","Los Angeles","Sydney"]},"V02":{"Name":"New Publishers, Inc.","Offices":["London","New York"]},"V01":{"Name":"Acme Books","Offices":["Seattle"]}}}
A single vendor:
{"VendorInfo":{"V03":{"Name":"Better Buy Books","Offices":["Tokyo","Los Angeles","Sydney"]}}}
First office location for a single vendor:
{"VendorInfo":{"V03":{"Offices":["Tokyo"]}}}
```

**注意**  
您可以使用 `toJSON` 方法将任意项目 (或其属性) 转换成 JSON 格式的字符串。以下代码检索多个顶级和嵌套属性，并以 JSON 格式输出结果。  

```
GetItemSpec spec = new GetItemSpec()
    .withPrimaryKey("Id", 210)
    .withProjectionExpression("VendorInfo.V01, Title, Price");

Item item = table.getItem(spec);
System.out.println(item.toJSON());
```
输出如下所示。  

```
{"VendorInfo":{"V01":{"Name":"Acme Books","Offices":["Seattle"]}},"Price":30,"Title":"Book 210 Title"}
```

## 批处理写入：放置和删除多个项目
<a name="BatchWriteDocumentAPIJava"></a>

*批量写入* 是指批量放置和删除多个项目。`batchWriteItem` 方法可让您通过一次 调用即可向一个或多个表中放置或从中删除多个项目。下面是使用 适用于 Java 的 AWS SDK 文档 API 放置或删除多个项目的步骤。

1. 创建 `DynamoDB` 类的实例。

1. 创建描述表的所有放置和删除操作的 `TableWriteItems` 类的实例。如果要在单个批量写入操作中写入到多个表，您必须为每个表创建一个 `TableWriteItems` 实例。

1. 通过提供您在之前步骤中创建的 `batchWriteItem` 对象，调用 `TableWriteItems` 方法。

1. 处理响应。您应该检查一下响应是否返回未处理的请求项目。如果达到预置吞吐量配额或发生其他临时错误，就可能会出现这种情况。此外，DynamoDB 还对可在请求中指定的请求大小和操作数进行限制。如果超出这些限制，DynamoDB 会拒绝请求。有关更多信息，请参阅 [Amazon DynamoDB 中的配额](ServiceQuotas.md)。

以下 Java 代码示例演示了上述步骤。本示例对两个表执行 `batchWriteItem` 操作：`Forum` 和 `Thread`。相应的 `TableWriteItems` 对象定义以下操作：
+ 在 `Forum` 表中放置一个项目。
+ 对 `Thread` 表放置和删除项目。

然后，代码调用 `batchWriteItem` 来执行操作。

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

TableWriteItems forumTableWriteItems = new TableWriteItems("Forum")
    .withItemsToPut(
        new Item()
            .withPrimaryKey("Name", "Amazon RDS")
            .withNumber("Threads", 0));

TableWriteItems threadTableWriteItems = new TableWriteItems("Thread")
    .withItemsToPut(
        new Item()
            .withPrimaryKey("ForumName","Amazon RDS","Subject","Amazon RDS Thread 1")
    .withHashAndRangeKeysToDelete("ForumName","Some partition key value", "Amazon S3", "Some sort key value");

BatchWriteItemOutcome outcome = dynamoDB.batchWriteItem(forumTableWriteItems, threadTableWriteItems);

// Code for checking unprocessed items is omitted in this example
```

要了解可工作的示例，请参阅 [示例：使用 适用于 Java 的 AWS SDK 文档 API 的批处理写入操作](batch-operation-document-api-java.md#JavaDocumentAPIBatchWrite)。

## 批处理获取：获取多个项目
<a name="JavaDocumentAPIBatchGetItem"></a>

`batchGetItem` 方法可让您检索一个或多个表中的多个项目。要检索单个项目，您可以使用 `getItem` 方法。

按照以下步骤进行操作：

1. 创建 `DynamoDB` 类的实例。

1. 创建描述要从表中检索的主键值列表的 `TableKeysAndAttributes` 类的实例。如果需要在单个批量获取操作中读取多个表，需要为每个表创建一个 `TableKeysAndAttributes` 实例。

1. 通过提供您在之前步骤中创建的 `batchGetItem` 对象，调用 `TableKeysAndAttributes` 方法。

以下 Java 代码示例演示了上述步骤。示例检索 `Forum` 表中的两个项目和 `Thread` 表中的三个项目。

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

    TableKeysAndAttributes forumTableKeysAndAttributes = new TableKeysAndAttributes(forumTableName);
    forumTableKeysAndAttributes.addHashOnlyPrimaryKeys("Name",
    "Amazon S3",
    "Amazon DynamoDB");

TableKeysAndAttributes threadTableKeysAndAttributes = new TableKeysAndAttributes(threadTableName);
threadTableKeysAndAttributes.addHashAndRangePrimaryKeys("ForumName", "Subject",
    "Amazon DynamoDB","DynamoDB Thread 1",
    "Amazon DynamoDB","DynamoDB Thread 2",
    "Amazon S3","S3 Thread 1");

BatchGetItemOutcome outcome = dynamoDB.batchGetItem(
    forumTableKeysAndAttributes, threadTableKeysAndAttributes);

for (String tableName : outcome.getTableItems().keySet()) {
    System.out.println("Items in table " + tableName);
    List<Item> items = outcome.getTableItems().get(tableName);
    for (Item item : items) {
        System.out.println(item);
    }
}
```

### 指定可选参数
<a name="BatchGetItemJavaDocumentAPIOptions"></a>

在使用 `batchGetItem` 时，除了必需的参数之外，您还可以指定可选参数。例如，可以随您定义的每个 `ProjectionExpression` 提供一个 `TableKeysAndAttributes`。这样您可以指定要从表中检索的属性。

以下 C\$1 代码示例从 `Forum` 表检索两个项目。`withProjectionExpression` 参数指定仅检索 `Threads` 属性。

**Example**  

```
TableKeysAndAttributes forumTableKeysAndAttributes = new TableKeysAndAttributes("Forum")
    .withProjectionExpression("Threads");

forumTableKeysAndAttributes.addHashOnlyPrimaryKeys("Name",
    "Amazon S3",
    "Amazon DynamoDB");

BatchGetItemOutcome outcome = dynamoDB.batchGetItem(forumTableKeysAndAttributes);
```

## 更新项目
<a name="JavaDocumentAPIItemUpdate"></a>

`updateItem` 对象的 `Table` 方法可以更新现有属性值，添加新属性，或者从现有项目中删除属性。

`updateItem` 方法的运行机制如下：
+ 如果项目不存在（表中不存在具有指定主键的项目），`updateItem` 会将新项目添加到表中
+ 如果项目存在，`updateItem` 会按照 `UpdateExpression` 参数指定的方式执行更新。

**注意**  
还可以使用 `putItem` 来“更新”项目。例如，如果您调用 `putItem` 向表中添加项目，但是已存在具有指定主键的项目，那么 `putItem` 将替换整个项目。如果现有项目中有属性，并且这些属性未在输入中指定，`putItem` 从项目中删除这些属性。  
通常，在您希望修改任何项目属性时，我们建议您使用 `updateItem`。`updateItem` 方法仅修改您在输入中指定的项目属性，项目中的其他属性将保持不变。

按照以下步骤进行操作：

1. 创建 `Table` 类的实例来代表要处理的表。

1. 调用 `updateTable` 实例的 `Table` 方法。必须指定要检索的项目的主键，同时指定描述要修改的属性以及如何修改这些属性的 `UpdateExpression`。

以下 Java 代码示例演示了上述任务。该代码更新 `ProductCatalog` 表中的书本项目。将新作者添加到 `Authors` 集中，并删除现有 `ISBN` 属性。另外还降低了价格 (-1)。

在 `ExpressionAttributeValues` 中使用 `UpdateExpression` 映射。在运行时，占位符 `:val1` 和 `:val2` 将被替换为 `Authors` 和 `Price` 的实际值。

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

Map<String, String> expressionAttributeNames = new HashMap<String, String>();
expressionAttributeNames.put("#A", "Authors");
expressionAttributeNames.put("#P", "Price");
expressionAttributeNames.put("#I", "ISBN");

Map<String, Object> expressionAttributeValues = new HashMap<String, Object>();
expressionAttributeValues.put(":val1",
    new HashSet<String>(Arrays.asList("Author YY","Author ZZ")));
expressionAttributeValues.put(":val2", 1);   //Price

UpdateItemOutcome outcome =  table.updateItem(
    "Id",          // key attribute name
    101,           // key attribute value
    "add #A :val1 set #P = #P - :val2 remove #I", // UpdateExpression
    expressionAttributeNames,
    expressionAttributeValues);
```

### 指定可选参数
<a name="UpdateItemJavaDocumentAPIOptions"></a>

除了必需的参数之外，您还可以为 `updateItem` 方法指定可选参数，其中包括为了执行更新而必须满足的条件。如果未满足指定条件，那么 适用于 Java 的 AWS SDK 会抛出 `ConditionalCheckFailedException`。例如，以下 Java 代码示例有条件地将书本物品价格更新为 25。它指定 `ConditionExpression`，后者声明仅当现有价格为 20 时才应更新价格。

**Example**  

```
Table table = dynamoDB.getTable("ProductCatalog");

Map<String, String> expressionAttributeNames = new HashMap<String, String>();
expressionAttributeNames.put("#P", "Price");

Map<String, Object> expressionAttributeValues = new HashMap<String, Object>();
expressionAttributeValues.put(":val1", 25);  // update Price to 25...
expressionAttributeValues.put(":val2", 20);  //...but only if existing Price is 20

UpdateItemOutcome outcome = table.updateItem(
    new PrimaryKey("Id",101),
    "set #P = :val1", // UpdateExpression
    "#P = :val2",     // ConditionExpression
    expressionAttributeNames,
    expressionAttributeValues);
```

### 原子计数器
<a name="AtomicCounterJavaDocumentAPI"></a>

您可以使用 `updateItem` 实现原子计数器，并使用该计数器来递增或递减现有属性的值而不会干扰其他写入请求。要递增原子计数器，请将 `UpdateExpression` 和 `set` 操作结合使用，以便将数值添加到类型为 `Number` 的现有属性。

以下示例演示了这一用法，将 `Quantity` 属性递增 1。它还演示在 `ExpressionAttributeNames` 中使用的 `UpdateExpression` 参数。

```
Table table = dynamoDB.getTable("ProductCatalog");

Map<String,String> expressionAttributeNames = new HashMap<String,String>();
expressionAttributeNames.put("#p", "PageCount");

Map<String,Object> expressionAttributeValues = new HashMap<String,Object>();
expressionAttributeValues.put(":val", 1);

UpdateItemOutcome outcome = table.updateItem(
    "Id", 121,
    "set #p = #p + :val",
    expressionAttributeNames,
    expressionAttributeValues);
```

## 删除项目
<a name="DeleteMidLevelJava"></a>

`deleteItem` 方法能删除表中的项目。您必须提供要删除的项目的主键。

按照以下步骤进行操作：

1. 创建 `DynamoDB` 客户端的实例。

1. 通过提供要删除的项目的键来调用 `deleteItem` 方法。

以下 Java 示例演示了这些任务。

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

DeleteItemOutcome outcome = table.deleteItem("Id", 101);
```

### 指定可选参数
<a name="DeleteItemJavaDocumentAPIOptions"></a>

您可以为 `deleteItem` 指定可选参数。例如，以下 Java 代码示例指定 `ConditionExpression`，声明只有当图书不再位于出版物中（`ProductCatalog` 属性为 false）时，才能删除 `InPublication` 中的图书项目。

**Example**  

```
Map<String,Object> expressionAttributeValues = new HashMap<String,Object>();
expressionAttributeValues.put(":val", false);

DeleteItemOutcome outcome = table.deleteItem("Id",103,
    "InPublication = :val",
    null, // ExpressionAttributeNames - not used in this example
    expressionAttributeValues);
```

# 示例：使用 适用于 Java 的 AWS SDK 文档 API 的 CRUD 操作
<a name="JavaDocumentAPICRUDExample"></a>

以下代码示例介绍对 Amazon DynamoDB 项目的 CRUD 操作。该示例创建一个项目、对其进行检索、执行多种更新，最终删除项目。

**注意**  
SDK for Java 还提供一个对象持久化模型，可用来将客户端类映射到 DynamoDB 表。该方法可以减少需要编写的代码数量。有关更多信息，请参阅 [Java 1.x：DynamoDBMapper](DynamoDBMapper.md)。

**注意**  
此代码示例假定您已按照 [为 DynamoDB 中的代码示例创建表和加载数据](SampleData.md) 部分的说明，将数据加载到您的帐户的 DynamoDB 中。  
有关运行以下示例的分步说明，请参阅 [Java 代码示例](CodeSamples.Java.md)。

```
package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DeleteItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.UpdateItemOutcome;
import com.amazonaws.services.dynamodbv2.document.spec.DeleteItemSpec;
import com.amazonaws.services.dynamodbv2.document.spec.UpdateItemSpec;
import com.amazonaws.services.dynamodbv2.document.utils.NameMap;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;
import com.amazonaws.services.dynamodbv2.model.ReturnValue;

public class DocumentAPIItemCRUDExample {

    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    static String tableName = "ProductCatalog";

    public static void main(String[] args) throws IOException {

        createItems();

        retrieveItem();

        // Perform various updates.
        updateMultipleAttributes();
        updateAddNewAttribute();
        updateExistingAttributeConditionally();

        // Delete the item.
        deleteItem();

    }

    private static void createItems() {

        Table table = dynamoDB.getTable(tableName);
        try {

            Item item = new Item().withPrimaryKey("Id", 120).withString("Title", "Book 120 Title")
                    .withString("ISBN", "120-1111111111")
                    .withStringSet("Authors", new HashSet<String>(Arrays.asList("Author12", "Author22")))
                    .withNumber("Price", 20).withString("Dimensions", "8.5x11.0x.75").withNumber("PageCount", 500)
                    .withBoolean("InPublication", false).withString("ProductCategory", "Book");
            table.putItem(item);

            item = new Item().withPrimaryKey("Id", 121).withString("Title", "Book 121 Title")
                    .withString("ISBN", "121-1111111111")
                    .withStringSet("Authors", new HashSet<String>(Arrays.asList("Author21", "Author 22")))
                    .withNumber("Price", 20).withString("Dimensions", "8.5x11.0x.75").withNumber("PageCount", 500)
                    .withBoolean("InPublication", true).withString("ProductCategory", "Book");
            table.putItem(item);

        } catch (Exception e) {
            System.err.println("Create items failed.");
            System.err.println(e.getMessage());

        }
    }

    private static void retrieveItem() {
        Table table = dynamoDB.getTable(tableName);

        try {

            Item item = table.getItem("Id", 120, "Id, ISBN, Title, Authors", null);

            System.out.println("Printing item after retrieving it....");
            System.out.println(item.toJSONPretty());

        } catch (Exception e) {
            System.err.println("GetItem failed.");
            System.err.println(e.getMessage());
        }

    }

    private static void updateAddNewAttribute() {
        Table table = dynamoDB.getTable(tableName);

        try {

            UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", 121)
                    .withUpdateExpression("set #na = :val1").withNameMap(new NameMap().with("#na", "NewAttribute"))
                    .withValueMap(new ValueMap().withString(":val1", "Some value"))
                    .withReturnValues(ReturnValue.ALL_NEW);

            UpdateItemOutcome outcome = table.updateItem(updateItemSpec);

            // Check the response.
            System.out.println("Printing item after adding new attribute...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Failed to add new attribute in " + tableName);
            System.err.println(e.getMessage());
        }
    }

    private static void updateMultipleAttributes() {

        Table table = dynamoDB.getTable(tableName);

        try {

            UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", 120)
                    .withUpdateExpression("add #a :val1 set #na=:val2")
                    .withNameMap(new NameMap().with("#a", "Authors").with("#na", "NewAttribute"))
                    .withValueMap(
                            new ValueMap().withStringSet(":val1", "Author YY", "Author ZZ").withString(":val2",
                                    "someValue"))
                    .withReturnValues(ReturnValue.ALL_NEW);

            UpdateItemOutcome outcome = table.updateItem(updateItemSpec);

            // Check the response.
            System.out.println("Printing item after multiple attribute update...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Failed to update multiple attributes in " + tableName);
            System.err.println(e.getMessage());

        }
    }

    private static void updateExistingAttributeConditionally() {

        Table table = dynamoDB.getTable(tableName);

        try {

            // Specify the desired price (25.00) and also the condition (price =
            // 20.00)

            UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", 120)
                    .withReturnValues(ReturnValue.ALL_NEW).withUpdateExpression("set #p = :val1")
                    .withConditionExpression("#p = :val2").withNameMap(new NameMap().with("#p", "Price"))
                    .withValueMap(new ValueMap().withNumber(":val1", 25).withNumber(":val2", 20));

            UpdateItemOutcome outcome = table.updateItem(updateItemSpec);

            // Check the response.
            System.out.println("Printing item after conditional update to new attribute...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Error updating item in " + tableName);
            System.err.println(e.getMessage());
        }
    }

    private static void deleteItem() {

        Table table = dynamoDB.getTable(tableName);

        try {

            DeleteItemSpec deleteItemSpec = new DeleteItemSpec().withPrimaryKey("Id", 120)
                    .withConditionExpression("#ip = :val").withNameMap(new NameMap().with("#ip", "InPublication"))
                    .withValueMap(new ValueMap().withBoolean(":val", false)).withReturnValues(ReturnValue.ALL_OLD);

            DeleteItemOutcome outcome = table.deleteItem(deleteItemSpec);

            // Check the response.
            System.out.println("Printing item that was deleted...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Error deleting item in " + tableName);
            System.err.println(e.getMessage());
        }
    }
}
```

# 示例：使用 适用于 Java 的 AWS SDK 文档 API 的批处理操作
<a name="batch-operation-document-api-java"></a>

本部分提供在 Amazon DynamoDB 中使用 适用于 Java 的 AWS SDK 文档 API 执行批量写入和批量获取操作的示例。

**注意**  
SDK for Java 还提供一个对象持久化模型，可用来将客户端类映射到 DynamoDB 表。该方法可以减少需要编写的代码数量。有关更多信息，请参阅 [Java 1.x：DynamoDBMapper](DynamoDBMapper.md)。

**Topics**
+ [示例：使用 适用于 Java 的 AWS SDK 文档 API 的批处理写入操作](#JavaDocumentAPIBatchWrite)
+ [示例：使用 适用于 Java 的 AWS SDK 文档 API 的批处理获取操作](#JavaDocumentAPIBatchGet)

## 示例：使用 适用于 Java 的 AWS SDK 文档 API 的批处理写入操作
<a name="JavaDocumentAPIBatchWrite"></a>

以下 Java 代码示例使用 `batchWriteItem` 方法执行以下放置和删除操作：
+ 在 `Forum` 表中放置一个项目。
+ 在 `Thread` 表中放置一个项目并删除一个项目。

在创建批量写入请求时，您可以就一个或多个表指定任意数量的放置和删除请求。但是，`batchWriteItem` 对批量写入请求的大小，以及单个批量写入操作中的放置和删除操作数量有限制。如果您的请求超出这些限制，请求会遭到拒绝。如果您的表的预置吞吐量不足，无法处理此请求，那么响应将返回未处理的请求项目。

以下示例查看响应，了解响应是否包含任何未处理的请求项目。如果存在，则循环返回，并重新发送包含请求中的未处理项目的 `batchWriteItem` 请求。如果您遵循该指南中的示例，则应已创建 `Forum` 和 `Thread` 表。您还能够以编程方式创建这些表和上传示例数据。有关更多信息，请参阅 [使用 适用于 Java 的 AWS SDK 创建表示例并上传数据](AppendixSampleDataCodeJava.md)。

有关测试以下示例的分步说明，请参阅 [Java 代码示例](CodeSamples.Java.md)。

**Example**  

```
package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.BatchWriteItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.TableWriteItems;
import com.amazonaws.services.dynamodbv2.model.WriteRequest;

public class DocumentAPIBatchWrite {

    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    static String forumTableName = "Forum";
    static String threadTableName = "Thread";

    public static void main(String[] args) throws IOException {

        writeMultipleItemsBatchWrite();

    }

    private static void writeMultipleItemsBatchWrite() {
        try {

            // Add a new item to Forum
            TableWriteItems forumTableWriteItems = new TableWriteItems(forumTableName) // Forum
                    .withItemsToPut(new Item().withPrimaryKey("Name", "Amazon RDS").withNumber("Threads", 0));

            // Add a new item, and delete an existing item, from Thread
            // This table has a partition key and range key, so need to specify
            // both of them
            TableWriteItems threadTableWriteItems = new TableWriteItems(threadTableName)
                    .withItemsToPut(
                            new Item().withPrimaryKey("ForumName", "Amazon RDS", "Subject", "Amazon RDS Thread 1")
                                    .withString("Message", "ElastiCache Thread 1 message")
                                    .withStringSet("Tags", new HashSet<String>(Arrays.asList("cache", "in-memory"))))
                    .withHashAndRangeKeysToDelete("ForumName", "Subject", "Amazon S3", "S3 Thread 100");

            System.out.println("Making the request.");
            BatchWriteItemOutcome outcome = dynamoDB.batchWriteItem(forumTableWriteItems, threadTableWriteItems);

            do {

                // Check for unprocessed keys which could happen if you exceed
                // provisioned throughput

                Map<String, List<WriteRequest>> unprocessedItems = outcome.getUnprocessedItems();

                if (outcome.getUnprocessedItems().size() == 0) {
                    System.out.println("No unprocessed items found");
                } else {
                    System.out.println("Retrieving the unprocessed items");
                    outcome = dynamoDB.batchWriteItemUnprocessed(unprocessedItems);
                }

            } while (outcome.getUnprocessedItems().size() > 0);

        } catch (Exception e) {
            System.err.println("Failed to retrieve items: ");
            e.printStackTrace(System.err);
        }

    }

}
```

## 示例：使用 适用于 Java 的 AWS SDK 文档 API 的批处理获取操作
<a name="JavaDocumentAPIBatchGet"></a>

以下 Java 代码示例使用 `batchGetItem` 方法检索 `Forum` 和 `Thread` 表中的多个项目。`BatchGetItemRequest` 为每个要获取的项目指定表名称和键列表。示例介绍通过打印检索到的项目来处理响应。

**注意**  
此代码示例假定您已将数据加载到您的帐户的 DynamoDB 中，方法是按照 [为 DynamoDB 中的代码示例创建表和加载数据](SampleData.md) 部分。  
有关运行以下示例的分步说明，请参阅 [Java 代码示例](CodeSamples.Java.md)。

**Example**  

```
package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.BatchGetItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.TableKeysAndAttributes;
import com.amazonaws.services.dynamodbv2.model.KeysAndAttributes;

public class DocumentAPIBatchGet {
    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    static String forumTableName = "Forum";
    static String threadTableName = "Thread";

    public static void main(String[] args) throws IOException {
        retrieveMultipleItemsBatchGet();
    }

    private static void retrieveMultipleItemsBatchGet() {

        try {

            TableKeysAndAttributes forumTableKeysAndAttributes = new TableKeysAndAttributes(forumTableName);
            // Add a partition key
            forumTableKeysAndAttributes.addHashOnlyPrimaryKeys("Name", "Amazon S3", "Amazon DynamoDB");

            TableKeysAndAttributes threadTableKeysAndAttributes = new TableKeysAndAttributes(threadTableName);
            // Add a partition key and a sort key
            threadTableKeysAndAttributes.addHashAndRangePrimaryKeys("ForumName", "Subject", "Amazon DynamoDB",
                    "DynamoDB Thread 1", "Amazon DynamoDB", "DynamoDB Thread 2", "Amazon S3", "S3 Thread 1");

            System.out.println("Making the request.");

            BatchGetItemOutcome outcome = dynamoDB.batchGetItem(forumTableKeysAndAttributes,
                    threadTableKeysAndAttributes);

            Map<String, KeysAndAttributes> unprocessed = null;

            do {
                for (String tableName : outcome.getTableItems().keySet()) {
                    System.out.println("Items in table " + tableName);
                    List<Item> items = outcome.getTableItems().get(tableName);
                    for (Item item : items) {
                        System.out.println(item.toJSONPretty());
                    }
                }

                // Check for unprocessed keys which could happen if you exceed
                // provisioned
                // throughput or reach the limit on response size.
                unprocessed = outcome.getUnprocessedKeys();

                if (unprocessed.isEmpty()) {
                    System.out.println("No unprocessed keys found");
                } else {
                    System.out.println("Retrieving the unprocessed keys");
                    outcome = dynamoDB.batchGetItemUnprocessed(unprocessed);
                }

            } while (!unprocessed.isEmpty());

        } catch (Exception e) {
            System.err.println("Failed to retrieve items.");
            System.err.println(e.getMessage());
        }

    }

}
```

# 示例：使用 适用于 Java 的 AWS SDK 文档 API 处理二进制类型属性
<a name="JavaDocumentAPIBinaryTypeExample"></a>

以下 Java 代码示例介绍如何处理二进制类型属性。示例介绍将项目添加到 `Reply` 表。项目包含存储压缩数据的二进制类型属性 (`ExtendedMessage`)。然后，示例检索该项目，并打印所有属性值。为方便说明，该示例使用 `GZIPOutputStream` 类压缩示例数据流，并将其分配至 `ExtendedMessage` 属性。检索到二进制属性后，使用 `GZIPInputStream` 类对其解压。

**注意**  
SDK for Java 还提供一个对象持久化模型，可用来将客户端类映射到 DynamoDB 表。该方法可以减少需要编写的代码数量。有关更多信息，请参阅 [Java 1.x：DynamoDBMapper](DynamoDBMapper.md)。

如果您已按照[为 DynamoDB 中的代码示例创建表和加载数据](SampleData.md)部分进行操作，您应当已经创建了 `Reply` 表。您还能够以编程方式创建此表。有关更多信息，请参阅 [使用 适用于 Java 的 AWS SDK 创建表示例并上传数据](AppendixSampleDataCodeJava.md)。

有关测试以下示例的分步说明，请参阅 [Java 代码示例](CodeSamples.Java.md)。

**Example**  

```
package com.amazonaws.codesamples.document;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.GetItemSpec;

public class DocumentAPIItemBinaryExample {

    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    static String tableName = "Reply";
    static SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

    public static void main(String[] args) throws IOException {
        try {

            // Format the primary key values
            String threadId = "Amazon DynamoDB#DynamoDB Thread 2";

            dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
            String replyDateTime = dateFormatter.format(new Date());

            // Add a new reply with a binary attribute type
            createItem(threadId, replyDateTime);

            // Retrieve the reply with a binary attribute type
            retrieveItem(threadId, replyDateTime);

            // clean up by deleting the item
            deleteItem(threadId, replyDateTime);
        } catch (Exception e) {
            System.err.println("Error running the binary attribute type example: " + e);
            e.printStackTrace(System.err);
        }
    }

    public static void createItem(String threadId, String replyDateTime) throws IOException {

        Table table = dynamoDB.getTable(tableName);

        // Craft a long message
        String messageInput = "Long message to be compressed in a lengthy forum reply";

        // Compress the long message
        ByteBuffer compressedMessage = compressString(messageInput.toString());

        table.putItem(new Item().withPrimaryKey("Id", threadId).withString("ReplyDateTime", replyDateTime)
                .withString("Message", "Long message follows").withBinary("ExtendedMessage", compressedMessage)
                .withString("PostedBy", "User A"));
    }

    public static void retrieveItem(String threadId, String replyDateTime) throws IOException {

        Table table = dynamoDB.getTable(tableName);

        GetItemSpec spec = new GetItemSpec().withPrimaryKey("Id", threadId, "ReplyDateTime", replyDateTime)
                .withConsistentRead(true);

        Item item = table.getItem(spec);

        // Uncompress the reply message and print
        String uncompressed = uncompressString(ByteBuffer.wrap(item.getBinary("ExtendedMessage")));

        System.out.println("Reply message:\n" + " Id: " + item.getString("Id") + "\n" + " ReplyDateTime: "
                + item.getString("ReplyDateTime") + "\n" + " PostedBy: " + item.getString("PostedBy") + "\n"
                + " Message: "
                + item.getString("Message") + "\n" + " ExtendedMessage (uncompressed): " + uncompressed + "\n");
    }

    public static void deleteItem(String threadId, String replyDateTime) {

        Table table = dynamoDB.getTable(tableName);
        table.deleteItem("Id", threadId, "ReplyDateTime", replyDateTime);
    }

    private static ByteBuffer compressString(String input) throws IOException {
        // Compress the UTF-8 encoded String into a byte[]
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPOutputStream os = new GZIPOutputStream(baos);
        os.write(input.getBytes("UTF-8"));
        os.close();
        baos.close();
        byte[] compressedBytes = baos.toByteArray();

        // The following code writes the compressed bytes to a ByteBuffer.
        // A simpler way to do this is by simply calling
        // ByteBuffer.wrap(compressedBytes);
        // However, the longer form below shows the importance of resetting the
        // position of the buffer
        // back to the beginning of the buffer if you are writing bytes directly
        // to it, since the SDK
        // will consider only the bytes after the current position when sending
        // data to DynamoDB.
        // Using the "wrap" method automatically resets the position to zero.
        ByteBuffer buffer = ByteBuffer.allocate(compressedBytes.length);
        buffer.put(compressedBytes, 0, compressedBytes.length);
        buffer.position(0); // Important: reset the position of the ByteBuffer
                            // to the beginning
        return buffer;
    }

    private static String uncompressString(ByteBuffer input) throws IOException {
        byte[] bytes = input.array();
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPInputStream is = new GZIPInputStream(bais);

        int chunkSize = 1024;
        byte[] buffer = new byte[chunkSize];
        int length = 0;
        while ((length = is.read(buffer, 0, chunkSize)) != -1) {
            baos.write(buffer, 0, length);
        }

        String result = new String(baos.toByteArray(), "UTF-8");

        is.close();
        baos.close();
        bais.close();

        return result;
    }
}
```

# 使用项目：.NET
<a name="LowLevelDotNetItemCRUD"></a>

您可以使用 适用于 .NET 的 AWS SDK 低级别 API 对表中的项目执行典型的创建、读取、更新和删除 (CRUD) 操作。以下是使用 .NET 低级 API 执行数据 CRUD 操作的常见步骤。

1. 创建 `AmazonDynamoDBClient` 类（客户端）的实例。

1. 在相应的请求对象中提供特定于操作的必需参数。

   例如，将 `PutItemRequest` 请求对象，并使用 `GetItemRequest` 检索现有项目时请求对象。

   您可以使用请求对象同时提供所需参数和可选参数。

1. 传入之前步骤创建的请求对象，运行客户端提供的适当方法。

   这些区域有：`AmazonDynamoDBClient` 客户端提供 `PutItem`、`GetItem`、`UpdateItem` 和 `DeleteItem` 方法进行 CRUD 操作。

**Topics**
+ [放置项目](#PutItemLowLevelAPIDotNet)
+ [获取项目](#GetItemLowLevelDotNET)
+ [更新项目](#UpdateItemLowLevelDotNet)
+ [原子计数器](#AtomicCounterLowLevelDotNet)
+ [删除项目](#DeleteMidLevelDotNet)
+ [批处理写入：放置和删除多个项目](#BatchWriteLowLevelDotNet)
+ [批处理获取：获取多个项目](#BatchGetLowLevelDotNet)
+ [示例：使用低级别 适用于 .NET 的 AWS SDK API 进行 CRUD 操作](LowLevelDotNetItemsExample.md)
+ [示例：使用低级 适用于 .NET 的 AWS SDK API 进行批处理操作](batch-operation-lowlevel-dotnet.md)
+ [示例：使用 适用于 .NET 的 AWS SDK 低级 API 处理二进制类型属性](LowLevelDotNetBinaryTypeExample.md)

## 放置项目
<a name="PutItemLowLevelAPIDotNet"></a>

`PutItem` 方法将项目上传到表。如果项目已存在，则会替换整个项目。

**注意**  
如果您不想替换整个项目，而只希望更新特定属性，那么您可以使用 `UpdateItem` 方法。有关更多信息，请参阅 [更新项目](#UpdateItemLowLevelDotNet)。

以下是使用低级别 .NET SDK API 上传项目的步骤。

1. 创建 `AmazonDynamoDBClient` 类的实例。

1. 提供所需的参数，方法是创建 `PutItemRequest` 类。

   要放置项目，您必须提供表名称和项目。

1. 通过提供您在之前步骤中创建的 `PutItemRequest` 对象，运行 `PutItem` 方法。

以下 C\$1 示例演示了上述步骤。该示例将一个项目上传到 `ProductCatalog` 表。

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new PutItemRequest
{
   TableName = tableName,
   Item = new Dictionary<string, AttributeValue>()
      {
          { "Id", new AttributeValue { N = "201" }},
          { "Title", new AttributeValue { S = "Book 201 Title" }},
          { "ISBN", new AttributeValue { S = "11-11-11-11" }},
          { "Price", new AttributeValue { S = "20.00" }},
          {
            "Authors",
            new AttributeValue
            { SS = new List<string>{"Author1", "Author2"}   }
          }
      }
};
client.PutItem(request);
```

在上一示例中，您上传的图书项目包含 `Id`、`Title`、`ISBN` 和 `Authors` 属性。请注意，`Id` 是数字类型属性，所有其他属性都是字符串类型。作者是 `String` 设置。

### 指定可选参数
<a name="PutItemLowLevelAPIDotNetOptions"></a>

您也可以使用 `PutItemRequest` 对象，如以下 C\$1 示例所示。该示例指定了以下可选参数：
+ `ExpressionAttributeNames`、`ExpressionAttributeValues` 和 `ConditionExpression` 指定只有当现有项目具有特定值 ISBN 属性时，才可替换该项目。
+ `ReturnValues` 参数，用于请求响应中的旧项目。

**Example**  

```
var request = new PutItemRequest
 {
   TableName = tableName,
   Item = new Dictionary<string, AttributeValue>()
               {
                   { "Id", new AttributeValue { N = "104" }},
                   { "Title", new AttributeValue { S = "Book 104  Title" }},
                   { "ISBN", new AttributeValue { S = "444-4444444444" }},
                   { "Authors",
                     new AttributeValue { SS = new List<string>{"Author3"}}}
               },
    // Optional parameters.
    ExpressionAttributeNames = new Dictionary<string,string>()
    {
        {"#I", "ISBN"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":isbn",new AttributeValue {S = "444-4444444444"}}
    },
    ConditionExpression = "#I = :isbn"

};
var response = client.PutItem(request);
```

有关更多信息，请参见 [PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html)。

## 获取项目
<a name="GetItemLowLevelDotNET"></a>

`GetItem` 方法检索项目。

**注意**  
要检索多个项目，您可以使用 `BatchGetItem` 方法。有关更多信息，请参阅 [批处理获取：获取多个项目](#BatchGetLowLevelDotNet)。

下面是使用低级 适用于 .NET 的 AWS SDK API 检索现有项目的步骤。

1. 创建 `AmazonDynamoDBClient` 类的实例。

1. 创建 `GetItemRequest` 类实例，提供所需的参数。

   要获取项目，您必须提供项目的表名称和主键。

1. 通过提供您在之前步骤中创建的 `GetItemRequest` 对象，运行 `GetItem` 方法。

以下 C\$1 示例演示了上述步骤。示例从 `ProductCatalog` 表检索项目。

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new GetItemRequest
 {
   TableName = tableName,
   Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "202" } } },
 };
 var response = client.GetItem(request);

// Check the response.
var result = response.GetItemResult;
var attributeMap = result.Item; // Attribute list in the response.
```

### 指定可选参数
<a name="GetItemLowLevelDotNETOptions"></a>

您也可以使用 `GetItemRequest` 对象提供可选参数，如以下 C\$1 示例所示。该示例指定了以下可选参数：
+ `ProjectionExpression` 参数，指定要检索的属性。
+ `ConsistentRead` 参数，执行强一致性读取。要了解有关读取一致性的更多信息，请参阅 [DynamoDB 读取一致性](HowItWorks.ReadConsistency.md)。

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new GetItemRequest
 {
   TableName = tableName,
   Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "202" } } },
   // Optional parameters.
   ProjectionExpression = "Id, ISBN, Title, Authors",
   ConsistentRead = true
 };

 var response = client.GetItem(request);

// Check the response.
var result = response.GetItemResult;
var attributeMap = result.Item;
```

有关更多信息，请参阅 [GetItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html)。

## 更新项目
<a name="UpdateItemLowLevelDotNet"></a>

`UpdateItem` 方法更新现有的项目（如果存在）。您可以使用 `UpdateItem` 操作更新现有属性值，添加新属性，或者从现有集合中删除属性。如果未找到具有指定主键的项目，将添加新项目。

`UpdateItem` 操作遵循以下指导原则：
+ 如果项目不存在，`UpdateItem` 会添加一个新项目 (使用输入中指定的主键)。
+ 如果项目存在，则 `UpdateItem` 按照以下方式应用更新：
  + 使用更新中的值替换现有属性值。
  + 如果您在输入中提供的属性不存在，系统就会为项目添加新属性。
  + 如果输入属性为 Null，系统会删除属性（如果存在）。
  + 如果您对 `Action` 使用 `ADD`，您可以将值添加到现有集合（字符串或数字集），或以数学方式从现有数字属性值中添加（使用正数）或减去（使用负数）。

**注意**  
`PutItem` 操作还可以执行更新。有关更多信息，请参阅 [放置项目](#PutItemLowLevelAPIDotNet)。例如，如果调用 `PutItem` 上传项目，并且主键存在，则 `PutItem` 操作会替换整个项目。如果现有项目中有属性，并且这些属性未在输入中指定，那么 `PutItem` 操作就会删除这些属性。但是，`UpdateItem` 仅更新指定的输入属性。该项目的任何其他现有属性都不会更改。

以下是使用低级 .NET SDK API 更新现有项目的步骤：

1. 创建 `AmazonDynamoDBClient` 类的实例。

1. 创建 `UpdateItemRequest` 类实例，提供所需的参数。

   这是描述所有更新（如添加属性、更新现有属性或删除属性）的请求对象。要删除现有属性，请将属性名称指定为 Null 值。

1. 通过提供您在之前步骤中创建的 `UpdateItemRequest` 对象，运行 `UpdateItem` 方法。

以下 C\$1 代码示例演示了上述步骤。示例更新 `ProductCatalog` 表中的书本项目。将新作者添加到 `Authors` 集合，删除现有 `ISBN` 属性。另外还降低了价格 (-1)。



```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new UpdateItemRequest
{
    TableName = tableName,
    Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "202" } } },
    ExpressionAttributeNames = new Dictionary<string,string>()
    {
        {"#A", "Authors"},
        {"#P", "Price"},
        {"#NA", "NewAttribute"},
        {"#I", "ISBN"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":auth",new AttributeValue { SS = {"Author YY","Author ZZ"}}},
        {":p",new AttributeValue {N = "1"}},
        {":newattr",new AttributeValue {S = "someValue"}},
    },

    // This expression does the following:
    // 1) Adds two new authors to the list
    // 2) Reduces the price
    // 3) Adds a new attribute to the item
    // 4) Removes the ISBN attribute from the item
    UpdateExpression = "ADD #A :auth SET #P = #P - :p, #NA = :newattr REMOVE #I"
};
var response = client.UpdateItem(request);
```

### 指定可选参数
<a name="UpdateItemLowLevelDotNETOptions"></a>

您也可以使用 `UpdateItemRequest` 对象提供可选参数，如以下 C\$1 示例所示。它指定以下两个可选参数：
+ `ExpressionAttributeValues` 和 `ConditionExpression`，指定仅当现有价格为 20.00 时才能更新价格。
+ `ReturnValues` 参数，用于请求响应中的更新项目。

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new UpdateItemRequest
{
    Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "202" } } },

    // Update price only if the current price is 20.00.
    ExpressionAttributeNames = new Dictionary<string,string>()
    {
        {"#P", "Price"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":newprice",new AttributeValue {N = "22"}},
        {":currprice",new AttributeValue {N = "20"}}
    },
    UpdateExpression = "SET #P = :newprice",
    ConditionExpression = "#P = :currprice",
    TableName = tableName,
    ReturnValues = "ALL_NEW" // Return all the attributes of the updated item.
};

var response = client.UpdateItem(request);
```

有关更多信息，请参见 [UpdateItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html)。

## 原子计数器
<a name="AtomicCounterLowLevelDotNet"></a>

您可以使用 `updateItem` 实现原子计数器，并使用该计数器来递增或递减现有属性的值而不会干扰其他写入请求。要更新原子计数器，请使用 `updateItem`，`UpdateExpression` 参数为 `Number` 类型属性，`ADD` 为 `Action`。

以下示例演示了这一用法，将 `Quantity` 属性递增 1。

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new UpdateItemRequest
{
    Key = new Dictionary<string, AttributeValue>() { { "Id", new AttributeValue { N = "121" } } },
    ExpressionAttributeNames = new Dictionary<string, string>()
    {
        {"#Q", "Quantity"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":incr",new AttributeValue {N = "1"}}
    },
    UpdateExpression = "SET #Q = #Q + :incr",
    TableName = tableName
};

var response = client.UpdateItem(request);
```

## 删除项目
<a name="DeleteMidLevelDotNet"></a>

`DeleteItem` 方法能删除表中的项目。

以下是使用低级 .NET SDK API 删除项目的步骤。

1. 创建 `AmazonDynamoDBClient` 类的实例。

1. 创建 `DeleteItemRequest` 类实例，提供所需的参数。

    要删除项目，需要表名和项目的主键。

1. 通过提供您在之前步骤中创建的 `DeleteItemRequest` 对象，运行 `DeleteItem` 方法。

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new DeleteItemRequest
{
    TableName = tableName,
    Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "201" } } },
};

var response = client.DeleteItem(request);
```

### 指定可选参数
<a name="DeleteItemLowLevelDotNETOptions"></a>

您也可以使用 `DeleteItemRequest` 对象提供可选参数，如以下 C\$1 代码示例所示。它指定以下两个可选参数：
+ `ExpressionAttributeValues` 和 `ConditionExpression`，指定仅当书籍项目不再在出版中时才可以删除（InPublisted 属性值为 false）。
+ `ReturnValues` 参数，请求响应中的删除项目。

**Example**  

```
var request = new DeleteItemRequest
{
    TableName = tableName,
    Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "201" } } },

    // Optional parameters.
    ReturnValues = "ALL_OLD",
    ExpressionAttributeNames = new Dictionary<string, string>()
    {
        {"#IP", "InPublication"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":inpub",new AttributeValue {BOOL = false}}
    },
    ConditionExpression = "#IP = :inpub"
};

var response = client.DeleteItem(request);
```

有关更多信息，请参阅 [DeleteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DeleteItem.html)。

## 批处理写入：放置和删除多个项目
<a name="BatchWriteLowLevelDotNet"></a>

*批量写入* 是指批量放置和删除多个项目。`BatchWriteItem` 方法可让您通过一次 调用即可向一个或多个表中放置或从中删除多个项目。以下是使用低级 .NET SDK API 检索多个项目的步骤。

1. 创建 `AmazonDynamoDBClient` 类的实例。

1. 创建 `BatchWriteItemRequest` 类实例，描述所有放入和删除操作。

1. 通过提供您在之前步骤中创建的 `BatchWriteItemRequest` 对象，运行 `BatchWriteItem` 方法。

1. 处理响应。您应该检查一下响应是否返回未处理的请求项目。如果达到预置吞吐量配额或发生其他临时错误，就可能会出现这种情况。此外，DynamoDB 还对可在请求中指定的请求大小和操作数进行限制。如果超出这些限制，DynamoDB 会拒绝请求。有关更多信息，请参阅 [BatchWriteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html)。

以下 C\$1 代码示例演示了上述步骤。该示例创建了一个 `BatchWriteItemRequest` 执行以下写入操作：
+ 在 `Forum` 表中放置一个项目。
+ 对 `Thread` 表放置和删除项目。

代码运行 `BatchWriteItem` 执行批处理操作。

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();

string table1Name = "Forum";
string table2Name = "Thread";

var request = new BatchWriteItemRequest
 {
   RequestItems = new Dictionary<string, List<WriteRequest>>
    {
      {
        table1Name, new List<WriteRequest>
        {
          new WriteRequest
          {
             PutRequest = new PutRequest
             {
                Item = new Dictionary<string,AttributeValue>
                {
                  { "Name", new AttributeValue { S = "Amazon S3 forum" } },
                  { "Threads", new AttributeValue { N = "0" }}
                }
             }
          }
        }
      } ,
      {
        table2Name, new List<WriteRequest>
        {
          new WriteRequest
          {
            PutRequest = new PutRequest
            {
               Item = new Dictionary<string,AttributeValue>
               {
                 { "ForumName", new AttributeValue { S = "Amazon S3 forum" } },
                 { "Subject", new AttributeValue { S = "My sample question" } },
                 { "Message", new AttributeValue { S = "Message Text." } },
                 { "KeywordTags", new AttributeValue { SS = new List<string> { "Amazon S3", "Bucket" }  } }
               }
            }
          },
          new WriteRequest
          {
             DeleteRequest = new DeleteRequest
             {
                Key = new Dictionary<string,AttributeValue>()
                {
                   { "ForumName", new AttributeValue { S = "Some forum name" } },
                   { "Subject", new AttributeValue { S = "Some subject" } }
                }
             }
          }
        }
      }
    }
 };
response = client.BatchWriteItem(request);
```

要了解可工作的示例，请参阅 [示例：使用低级 适用于 .NET 的 AWS SDK API 进行批处理操作](batch-operation-lowlevel-dotnet.md)。

## 批处理获取：获取多个项目
<a name="BatchGetLowLevelDotNet"></a>

`BatchGetItem` 方法可让您检索一个或多个表中的多个项目。

**注意**  
要检索单个项目，您可以使用 `GetItem` 方法。

以下是使用低级 适用于 .NET 的 AWS SDK API 检索多个项目的步骤。

1. 创建 `AmazonDynamoDBClient` 类的实例。

1. 创建 `BatchGetItemRequest` 类实例，提供所需的参数。

   要检索多个项目，需要表名和主键值列表。

1. 通过提供您在之前步骤中创建的 `BatchGetItemRequest` 对象，运行 `BatchGetItem` 方法。

1. 处理响应。您应检查一下是否存在任何未处理的键，如果达到了预置吞吐量配额或发生某些其他临时错误，就可能会出现这种情况。

以下 C\$1 代码示例演示了上述步骤。该示例从两个表 `Forum` 和 `Thread` 检索项目。请求指定 `Forum` 表中两个项目和 `Thread` 表中三个项目。响应包括两个表中的项目。代码显示了如何处理响应。



```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();

string table1Name = "Forum";
string table2Name = "Thread";

var request = new BatchGetItemRequest
{
  RequestItems = new Dictionary<string, KeysAndAttributes>()
  {
    { table1Name,
      new KeysAndAttributes
      {
        Keys = new List<Dictionary<string, AttributeValue>>()
        {
          new Dictionary<string, AttributeValue>()
          {
            { "Name", new AttributeValue { S = "DynamoDB" } }
          },
          new Dictionary<string, AttributeValue>()
          {
            { "Name", new AttributeValue { S = "Amazon S3" } }
          }
        }
      }
    },
    {
      table2Name,
      new KeysAndAttributes
      {
        Keys = new List<Dictionary<string, AttributeValue>>()
        {
          new Dictionary<string, AttributeValue>()
          {
            { "ForumName", new AttributeValue { S = "DynamoDB" } },
            { "Subject", new AttributeValue { S = "DynamoDB Thread 1" } }
          },
          new Dictionary<string, AttributeValue>()
          {
            { "ForumName", new AttributeValue { S = "DynamoDB" } },
            { "Subject", new AttributeValue { S = "DynamoDB Thread 2" } }
          },
          new Dictionary<string, AttributeValue>()
          {
            { "ForumName", new AttributeValue { S = "Amazon S3" } },
            { "Subject", new AttributeValue { S = "Amazon S3 Thread 1" } }
          }
        }
      }
    }
  }
};

var response = client.BatchGetItem(request);

// Check the response.
var result = response.BatchGetItemResult;
var responses = result.Responses; // The attribute list in the response.

var table1Results = responses[table1Name];
Console.WriteLine("Items in table {0}" + table1Name);
foreach (var item1 in table1Results.Items)
{
  PrintItem(item1);
}

var table2Results = responses[table2Name];
Console.WriteLine("Items in table {1}" + table2Name);
foreach (var item2 in table2Results.Items)
{
  PrintItem(item2);
}
// Any unprocessed keys? could happen if you exceed ProvisionedThroughput or some other error.
Dictionary<string, KeysAndAttributes> unprocessedKeys = result.UnprocessedKeys;
foreach (KeyValuePair<string, KeysAndAttributes> pair in unprocessedKeys)
{
    Console.WriteLine(pair.Key, pair.Value);
}
```



### 指定可选参数
<a name="BatchGetItemLowLevelDotNETOptions"></a>

您也可以使用 `BatchGetItemRequest` 对象提供可选参数，如以下 C\$1 代码示例所示。示例从 `Forum` 表检索两个项目。其中指定了以下可选参数：
+  `ProjectionExpression` 参数，指定要检索的属性。

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();

string table1Name = "Forum";

var request = new BatchGetItemRequest
{
  RequestItems = new Dictionary<string, KeysAndAttributes>()
  {
    { table1Name,
      new KeysAndAttributes
      {
        Keys = new List<Dictionary<string, AttributeValue>>()
        {
          new Dictionary<string, AttributeValue>()
          {
            { "Name", new AttributeValue { S = "DynamoDB" } }
          },
          new Dictionary<string, AttributeValue>()
          {
            { "Name", new AttributeValue { S = "Amazon S3" } }
          }
        }
      },
      // Optional - name of an attribute to retrieve.
      ProjectionExpression = "Title"
    }
  }
};

var response = client.BatchGetItem(request);
```

有关更多信息，请参阅 [BatchGetItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html)。

# 示例：使用低级别 适用于 .NET 的 AWS SDK API 进行 CRUD 操作
<a name="LowLevelDotNetItemsExample"></a>

以下 C\$1 代码示例介绍对 Amazon DynamoDB 项目的 CRUD 操作。该示例将项目添加到 `ProductCatalog` 表、对其进行检索、执行多种更新，最终删除项目。如果您尚未创建此表，也可以编程方式进行创建。有关更多信息，请参阅 [创建示例表并使用 适用于 .NET 的 AWS SDK 上传数据](AppendixSampleDataCodeDotNET.md)。

有关测试以下示例的分步说明，请参阅 [.NET 代码示例](CodeSamples.DotNet.md)。

**Example**  

```
using System;
using System.Collections.Generic;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;
using Amazon.SecurityToken;

namespace com.amazonaws.codesamples
{
    class LowLevelItemCRUDExample
    {
        private static string tableName = "ProductCatalog";
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();

        static void Main(string[] args)
        {
            try
            {
                CreateItem();
                RetrieveItem();

                // Perform various updates.
                UpdateMultipleAttributes();
                UpdateExistingAttributeConditionally();

                // Delete item.
                DeleteItem();
                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
        }

        private static void CreateItem()
        {
            var request = new PutItemRequest
            {
                TableName = tableName,
                Item = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      N = "1000"
                  }},
                { "Title", new AttributeValue {
                      S = "Book 201 Title"
                  }},
                { "ISBN", new AttributeValue {
                      S = "11-11-11-11"
                  }},
                { "Authors", new AttributeValue {
                      SS = new List<string>{"Author1", "Author2" }
                  }},
                { "Price", new AttributeValue {
                      N = "20.00"
                  }},
                { "Dimensions", new AttributeValue {
                      S = "8.5x11.0x.75"
                  }},
                { "InPublication", new AttributeValue {
                      BOOL = false
                  } }
            }
            };
            client.PutItem(request);
        }

        private static void RetrieveItem()
        {
            var request = new GetItemRequest
            {
                TableName = tableName,
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      N = "1000"
                  } }
            },
                ProjectionExpression = "Id, ISBN, Title, Authors",
                ConsistentRead = true
            };
            var response = client.GetItem(request);

            // Check the response.
            var attributeList = response.Item; // attribute list in the response.
            Console.WriteLine("\nPrinting item after retrieving it ............");
            PrintItem(attributeList);
        }

        private static void UpdateMultipleAttributes()
        {
            var request = new UpdateItemRequest
            {
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      N = "1000"
                  } }
            },
                // Perform the following updates:
                // 1) Add two new authors to the list
                // 1) Set a new attribute
                // 2) Remove the ISBN attribute
                ExpressionAttributeNames = new Dictionary<string, string>()
            {
                {"#A","Authors"},
                {"#NA","NewAttribute"},
                {"#I","ISBN"}
            },
                ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
            {
                {":auth",new AttributeValue {
                     SS = {"Author YY", "Author ZZ"}
                 }},
                {":new",new AttributeValue {
                     S = "New Value"
                 }}
            },

                UpdateExpression = "ADD #A :auth SET #NA = :new REMOVE #I",

                TableName = tableName,
                ReturnValues = "ALL_NEW" // Give me all attributes of the updated item.
            };
            var response = client.UpdateItem(request);

            // Check the response.
            var attributeList = response.Attributes; // attribute list in the response.
                                                     // print attributeList.
            Console.WriteLine("\nPrinting item after multiple attribute update ............");
            PrintItem(attributeList);
        }

        private static void UpdateExistingAttributeConditionally()
        {
            var request = new UpdateItemRequest
            {
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      N = "1000"
                  } }
            },
                ExpressionAttributeNames = new Dictionary<string, string>()
            {
                {"#P", "Price"}
            },
                ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
            {
                {":newprice",new AttributeValue {
                     N = "22.00"
                 }},
                {":currprice",new AttributeValue {
                     N = "20.00"
                 }}
            },
                // This updates price only if current price is 20.00.
                UpdateExpression = "SET #P = :newprice",
                ConditionExpression = "#P = :currprice",

                TableName = tableName,
                ReturnValues = "ALL_NEW" // Give me all attributes of the updated item.
            };
            var response = client.UpdateItem(request);

            // Check the response.
            var attributeList = response.Attributes; // attribute list in the response.
            Console.WriteLine("\nPrinting item after updating price value conditionally ............");
            PrintItem(attributeList);
        }

        private static void DeleteItem()
        {
            var request = new DeleteItemRequest
            {
                TableName = tableName,
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      N = "1000"
                  } }
            },

                // Return the entire item as it appeared before the update.
                ReturnValues = "ALL_OLD",
                ExpressionAttributeNames = new Dictionary<string, string>()
            {
                {"#IP", "InPublication"}
            },
                ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
            {
                {":inpub",new AttributeValue {
                     BOOL = false
                 }}
            },
                ConditionExpression = "#IP = :inpub"
            };

            var response = client.DeleteItem(request);

            // Check the response.
            var attributeList = response.Attributes; // Attribute list in the response.
                                                     // Print item.
            Console.WriteLine("\nPrinting item that was just deleted ............");
            PrintItem(attributeList);
        }

        private static void PrintItem(Dictionary<string, AttributeValue> attributeList)
        {
            foreach (KeyValuePair<string, AttributeValue> kvp in attributeList)
            {
                string attributeName = kvp.Key;
                AttributeValue value = kvp.Value;

                Console.WriteLine(
                    attributeName + " " +
                    (value.S == null ? "" : "S=[" + value.S + "]") +
                    (value.N == null ? "" : "N=[" + value.N + "]") +
                    (value.SS == null ? "" : "SS=[" + string.Join(",", value.SS.ToArray()) + "]") +
                    (value.NS == null ? "" : "NS=[" + string.Join(",", value.NS.ToArray()) + "]")
                    );
            }
            Console.WriteLine("************************************************");
        }
    }
}
```

# 示例：使用低级 适用于 .NET 的 AWS SDK API 进行批处理操作
<a name="batch-operation-lowlevel-dotnet"></a>

**Topics**
+ [示例：使用 适用于 .NET 的 AWS SDK 低级 API 的批处理写入操作](#batch-write-low-level-dotnet)
+ [示例：使用 适用于 .NET 的 AWS SDK 低级 API 的批处理获取操作](#LowLevelDotNetBatchGet)

本节提供 Amazon DynamoDB 支持的批量操作示例，*批处理写入*和*批处理获取*。

## 示例：使用 适用于 .NET 的 AWS SDK 低级 API 的批处理写入操作
<a name="batch-write-low-level-dotnet"></a>

以下 C\$1 代码示例使用 `BatchWriteItem` 方法执行以下放置和删除操作：
+ 在 `Forum` 表中放置一个项目。
+ 在 `Thread` 表中放置一个项目并删除一个项目。

在创建批量写入请求时，您可以就一个或多个表指定任意数量的放置和删除请求。但是，DynamoDB `BatchWriteItem` 对批量写入请求的大小，以及单个批量写入操作中的放置和删除操作数量有限制。有关更多信息，请参阅 [BatchWriteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html)。如果您的请求超出这些限制，请求会遭到拒绝。如果您的表的预置吞吐量不足，无法处理此请求，那么响应将返回未处理的请求项目。

以下示例查看响应，了解响应是否包含任何未处理的请求项目。如果存在，则循环返回，并重新发送包含请求中的未处理项目的 `BatchWriteItem` 请求。您还能够以编程方式创建这些表和上传示例数据。有关更多信息，请参阅 [创建示例表并使用 适用于 .NET 的 AWS SDK 上传数据](AppendixSampleDataCodeDotNET.md)。

有关测试以下示例的分步说明，请参阅 [.NET 代码示例](CodeSamples.DotNet.md)。

**Example**  

```
using System;
using System.Collections.Generic;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;

namespace com.amazonaws.codesamples
{
    class LowLevelBatchWrite
    {
        private static string table1Name = "Forum";
        private static string table2Name = "Thread";
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();

        static void Main(string[] args)
        {
            try
            {
                TestBatchWrite();
            }
            catch (AmazonServiceException e) { Console.WriteLine(e.Message); }
            catch (Exception e) { Console.WriteLine(e.Message); }

            Console.WriteLine("To continue, press Enter");
            Console.ReadLine();
        }

        private static void TestBatchWrite()
        {
            var request = new BatchWriteItemRequest
            {
                ReturnConsumedCapacity = "TOTAL",
                RequestItems = new Dictionary<string, List<WriteRequest>>
            {
                {
                    table1Name, new List<WriteRequest>
                    {
                        new WriteRequest
                        {
                            PutRequest = new PutRequest
                            {
                                Item = new Dictionary<string, AttributeValue>
                                {
                                    { "Name", new AttributeValue {
                                          S = "S3 forum"
                                      } },
                                    { "Threads", new AttributeValue {
                                          N = "0"
                                      }}
                                }
                            }
                        }
                    }
                },
                {
                    table2Name, new List<WriteRequest>
                    {
                        new WriteRequest
                        {
                            PutRequest = new PutRequest
                            {
                                Item = new Dictionary<string, AttributeValue>
                                {
                                    { "ForumName", new AttributeValue {
                                          S = "S3 forum"
                                      } },
                                    { "Subject", new AttributeValue {
                                          S = "My sample question"
                                      } },
                                    { "Message", new AttributeValue {
                                          S = "Message Text."
                                      } },
                                    { "KeywordTags", new AttributeValue {
                                          SS = new List<string> { "S3", "Bucket" }
                                      } }
                                }
                            }
                        },
                        new WriteRequest
                        {
                            // For the operation to delete an item, if you provide a primary key value
                            // that does not exist in the table, there is no error, it is just a no-op.
                            DeleteRequest = new DeleteRequest
                            {
                                Key = new Dictionary<string, AttributeValue>()
                                {
                                    { "ForumName",  new AttributeValue {
                                          S = "Some partition key value"
                                      } },
                                    { "Subject", new AttributeValue {
                                          S = "Some sort key value"
                                      } }
                                }
                            }
                        }
                    }
                }
            }
            };

            CallBatchWriteTillCompletion(request);
        }

        private static void CallBatchWriteTillCompletion(BatchWriteItemRequest request)
        {
            BatchWriteItemResponse response;

            int callCount = 0;
            do
            {
                Console.WriteLine("Making request");
                response = client.BatchWriteItem(request);
                callCount++;

                // Check the response.

                var tableConsumedCapacities = response.ConsumedCapacity;
                var unprocessed = response.UnprocessedItems;

                Console.WriteLine("Per-table consumed capacity");
                foreach (var tableConsumedCapacity in tableConsumedCapacities)
                {
                    Console.WriteLine("{0} - {1}", tableConsumedCapacity.TableName, tableConsumedCapacity.CapacityUnits);
                }

                Console.WriteLine("Unprocessed");
                foreach (var unp in unprocessed)
                {
                    Console.WriteLine("{0} - {1}", unp.Key, unp.Value.Count);
                }
                Console.WriteLine();

                // For the next iteration, the request will have unprocessed items.
                request.RequestItems = unprocessed;
            } while (response.UnprocessedItems.Count > 0);

            Console.WriteLine("Total # of batch write API calls made: {0}", callCount);
        }
    }
}
```

## 示例：使用 适用于 .NET 的 AWS SDK 低级 API 的批处理获取操作
<a name="LowLevelDotNetBatchGet"></a>

以下 Java 代码示例使用 `BatchGetItem` 方法检索 Amazon DynamoDB 中的 `Forum` 和 `Thread` 表中的多个项目。`BatchGetItemRequest` 指定表名称和每个表的主键列表。示例介绍通过打印检索到的项目来处理响应。

有关测试以下示例的分步说明，请参阅 [.NET 代码示例](CodeSamples.DotNet.md)。

**Example**  

```
using System;
using System.Collections.Generic;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;

namespace com.amazonaws.codesamples
{
    class LowLevelBatchGet
    {
        private static string table1Name = "Forum";
        private static string table2Name = "Thread";
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();

        static void Main(string[] args)
        {
            try
            {
                RetrieveMultipleItemsBatchGet();

                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
            catch (AmazonServiceException e) { Console.WriteLine(e.Message); }
            catch (Exception e) { Console.WriteLine(e.Message); }
        }

        private static void RetrieveMultipleItemsBatchGet()
        {
            var request = new BatchGetItemRequest
            {
                RequestItems = new Dictionary<string, KeysAndAttributes>()
            {
                { table1Name,
                  new KeysAndAttributes
                  {
                      Keys = new List<Dictionary<string, AttributeValue> >()
                      {
                          new Dictionary<string, AttributeValue>()
                          {
                              { "Name", new AttributeValue {
                            S = "Amazon DynamoDB"
                        } }
                          },
                          new Dictionary<string, AttributeValue>()
                          {
                              { "Name", new AttributeValue {
                            S = "Amazon S3"
                        } }
                          }
                      }
                  }},
                {
                    table2Name,
                    new KeysAndAttributes
                    {
                        Keys = new List<Dictionary<string, AttributeValue> >()
                        {
                            new Dictionary<string, AttributeValue>()
                            {
                                { "ForumName", new AttributeValue {
                                      S = "Amazon DynamoDB"
                                  } },
                                { "Subject", new AttributeValue {
                                      S = "DynamoDB Thread 1"
                                  } }
                            },
                            new Dictionary<string, AttributeValue>()
                            {
                                { "ForumName", new AttributeValue {
                                      S = "Amazon DynamoDB"
                                  } },
                                { "Subject", new AttributeValue {
                                      S = "DynamoDB Thread 2"
                                  } }
                            },
                            new Dictionary<string, AttributeValue>()
                            {
                                { "ForumName", new AttributeValue {
                                      S = "Amazon S3"
                                  } },
                                { "Subject", new AttributeValue {
                                      S = "S3 Thread 1"
                                  } }
                            }
                        }
                    }
                }
            }
            };

            BatchGetItemResponse response;
            do
            {
                Console.WriteLine("Making request");
                response = client.BatchGetItem(request);

                // Check the response.
                var responses = response.Responses; // Attribute list in the response.

                foreach (var tableResponse in responses)
                {
                    var tableResults = tableResponse.Value;
                    Console.WriteLine("Items retrieved from table {0}", tableResponse.Key);
                    foreach (var item1 in tableResults)
                    {
                        PrintItem(item1);
                    }
                }

                // Any unprocessed keys? could happen if you exceed ProvisionedThroughput or some other error.
                Dictionary<string, KeysAndAttributes> unprocessedKeys = response.UnprocessedKeys;
                foreach (var unprocessedTableKeys in unprocessedKeys)
                {
                    // Print table name.
                    Console.WriteLine(unprocessedTableKeys.Key);
                    // Print unprocessed primary keys.
                    foreach (var key in unprocessedTableKeys.Value.Keys)
                    {
                        PrintItem(key);
                    }
                }

                request.RequestItems = unprocessedKeys;
            } while (response.UnprocessedKeys.Count > 0);
        }

        private static void PrintItem(Dictionary<string, AttributeValue> attributeList)
        {
            foreach (KeyValuePair<string, AttributeValue> kvp in attributeList)
            {
                string attributeName = kvp.Key;
                AttributeValue value = kvp.Value;

                Console.WriteLine(
                    attributeName + " " +
                    (value.S == null ? "" : "S=[" + value.S + "]") +
                    (value.N == null ? "" : "N=[" + value.N + "]") +
                    (value.SS == null ? "" : "SS=[" + string.Join(",", value.SS.ToArray()) + "]") +
                    (value.NS == null ? "" : "NS=[" + string.Join(",", value.NS.ToArray()) + "]")
                    );
            }
            Console.WriteLine("************************************************");
        }
    }
}
```

# 示例：使用 适用于 .NET 的 AWS SDK 低级 API 处理二进制类型属性
<a name="LowLevelDotNetBinaryTypeExample"></a>

以下 C\$1 代码示例介绍如何处理二进制类型属性。示例介绍将项目添加到 `Reply` 表。项目包含存储压缩数据的二进制类型属性 (`ExtendedMessage`)。然后，示例检索该项目，并打印所有属性值。为方便说明，该示例使用 `GZipStream` 类压缩示例数据流，分配至 `ExtendedMessage` 属性，输出属性值时解压缩。

有关测试以下示例的分步说明，请参阅 [.NET 代码示例](CodeSamples.DotNet.md)。

**Example**  

```
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;

namespace com.amazonaws.codesamples
{
    class LowLevelItemBinaryExample
    {
        private static string tableName = "Reply";
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();

        static void Main(string[] args)
        {
            // Reply table primary key.
            string replyIdPartitionKey = "Amazon DynamoDB#DynamoDB Thread 1";
            string replyDateTimeSortKey = Convert.ToString(DateTime.UtcNow);

            try
            {
                CreateItem(replyIdPartitionKey, replyDateTimeSortKey);
                RetrieveItem(replyIdPartitionKey, replyDateTimeSortKey);
                // Delete item.
                DeleteItem(replyIdPartitionKey, replyDateTimeSortKey);
                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
            catch (AmazonDynamoDBException e) { Console.WriteLine(e.Message); }
            catch (AmazonServiceException e) { Console.WriteLine(e.Message); }
            catch (Exception e) { Console.WriteLine(e.Message); }
        }

        private static void CreateItem(string partitionKey, string sortKey)
        {
            MemoryStream compressedMessage = ToGzipMemoryStream("Some long extended message to compress.");
            var request = new PutItemRequest
            {
                TableName = tableName,
                Item = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      S = partitionKey
                  }},
                { "ReplyDateTime", new AttributeValue {
                      S = sortKey
                  }},
                { "Subject", new AttributeValue {
                      S = "Binary type "
                  }},
                { "Message", new AttributeValue {
                      S = "Some message about the binary type"
                  }},
                { "ExtendedMessage", new AttributeValue {
                      B = compressedMessage
                  }}
            }
            };
            client.PutItem(request);
        }

        private static void RetrieveItem(string partitionKey, string sortKey)
        {
            var request = new GetItemRequest
            {
                TableName = tableName,
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      S = partitionKey
                  } },
                { "ReplyDateTime", new AttributeValue {
                      S = sortKey
                  } }
            },
                ConsistentRead = true
            };
            var response = client.GetItem(request);

            // Check the response.
            var attributeList = response.Item; // attribute list in the response.
            Console.WriteLine("\nPrinting item after retrieving it ............");

            PrintItem(attributeList);
        }

        private static void DeleteItem(string partitionKey, string sortKey)
        {
            var request = new DeleteItemRequest
            {
                TableName = tableName,
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      S = partitionKey
                  } },
                { "ReplyDateTime", new AttributeValue {
                      S = sortKey
                  } }
            }
            };
            var response = client.DeleteItem(request);
        }

        private static void PrintItem(Dictionary<string, AttributeValue> attributeList)
        {
            foreach (KeyValuePair<string, AttributeValue> kvp in attributeList)
            {
                string attributeName = kvp.Key;
                AttributeValue value = kvp.Value;

                Console.WriteLine(
                    attributeName + " " +
                    (value.S == null ? "" : "S=[" + value.S + "]") +
                    (value.N == null ? "" : "N=[" + value.N + "]") +
                    (value.SS == null ? "" : "SS=[" + string.Join(",", value.SS.ToArray()) + "]") +
                    (value.NS == null ? "" : "NS=[" + string.Join(",", value.NS.ToArray()) + "]") +
                    (value.B == null ? "" : "B=[" + FromGzipMemoryStream(value.B) + "]")
                    );
            }
            Console.WriteLine("************************************************");
        }

        private static MemoryStream ToGzipMemoryStream(string value)
        {
            MemoryStream output = new MemoryStream();
            using (GZipStream zipStream = new GZipStream(output, CompressionMode.Compress, true))
            using (StreamWriter writer = new StreamWriter(zipStream))
            {
                writer.Write(value);
            }
            return output;
        }

        private static string FromGzipMemoryStream(MemoryStream stream)
        {
            using (GZipStream zipStream = new GZipStream(stream, CompressionMode.Decompress))
            using (StreamReader reader = new StreamReader(zipStream))
            {
                return reader.ReadToEnd();
            }
        }
    }
}
```