

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 在 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 SDKs的範例程式碼。

**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 個有意義位數。前後的零會截去。數字大小大約是 *(屬性名稱的 UTF-8 編碼位元組數目) \$1 (每兩個有效位數 1 位元組) \$1 (1 位元組)*。
+ 必須先以 base64 格式編碼二進位值，才能將它傳送至 DynamoDB，但使用值的原始位元組長度來計算大小。二進制屬性大小是 *(屬性名稱的 UTF-8 編碼位元組數目) \$1 (原始位元組數目)。*
+ Null 屬性或布林值屬性的大小是 *(屬性名稱的 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*，表示若項目尚未存在，它會自動建立項目。
+ `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` 請求包含兩個 PUT 請求和四個刪除請求，則 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 範例會將`Price`產品的 增加 5。在此範例中，在更新計數器之前已知該項目存在。因為 `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_tw/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_tw/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"}
}
```

Alice 的更新會成功，因為條件評估的結果為 true。

接下來，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` 請求將項目的 `Price` 增加 3，但只有在目前的 `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 中，您可以使用*表達式*指定要從項目讀取的屬性、在滿足條件時寫入資料、指定如何更新項目、定義查詢，以及篩選查詢的結果。

本資料表說明基本表達式語法及可用的表達式類型。


| 表達式類型 | Description | 
| --- | --- | 
| 投射表達式 | 使用 GetItem、Query 或 Scan 等操作時，投影表達式會識別您要從項目擷取的屬性。 | 
| 條件表達式 | 使用 PutItem、UpdateItem 和 DeleteItem 等操作時，條件表達式會判定應修改的項目。 | 
| 更新表達式 | 更新表達式會指定 UpdateItem 如何修改項目的屬性，例如設定純量值或將元素從清單或映射中刪除。 | 
| 索引鍵條件表達式 | 索引鍵條件表達式會判定查詢要讀取哪些資料表或索引的項目。 | 
| 篩選條件表達式 | 篩選條件表達式會判定要傳回哪些 Query 結果的項目。所有其他結果皆會捨棄。 | 

如需表達式語法的相關資訊，以及每種表達式類型的詳細資訊，請參閱下列各節。

**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] 代表清單中的第一個元素，[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 允許您使用點字元和其他特殊字元，例如連字號 (「-」) 作為屬性名稱的一部分。這在某些情況下可能會模棱兩可。為了示範，假設您想要從 `ProductCatalog` 項目擷取 `Safety.Warning` 屬性 (請參閱[在 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 會依預設傳回所有項目屬性。若只要取得部分而非全部屬性，請使用投射表達式。

*投射表達式*是識別所需屬性的字串。若要擷取單一屬性，請指定其名稱。若為多個屬性，則必須以逗號分隔名稱。

以下是根據 [在 DynamoDB 中使用表達式時參考項目屬性](Expressions.Attributes.md) 中的 `ProductCatalog` 項目而來的一些投射表達式範例：
+ 單一最上層屬性。

  `Title `
+ 三個最上層屬性。DynamoDB 會擷取整個 `Color` 設定。

  `Title, Price, Color`
+ 四個最上層屬性。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` 關鍵字。您可以依任意順序在更新表達式中包含其中任何子句。不過，每個動作關鍵字都只能出現一次。

在每個子句內，會有以逗號分隔的一或多個動作。每個動作都會代表資料修改。

本節中的範例是以[在 DynamoDB 中使用投影表達式](Expressions.ProjectionExpressions.md)中所顯示的 `ProductCatalog` 項目為基礎。

以下主題涵蓋了 `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] 代表清單中的第一個元素、[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.FiveStar`) 不存在時更新巢狀屬性 （例如 `ProductReviews`)，DynamoDB 會傳回 `ValidationException`，並顯示*「更新表達式中提供的文件路徑無效，無法更新」訊息。*  
建立稍後更新巢狀對應屬性的項目時，請初始化父屬性的空對應。例如：  

```
{
    "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` 的*開頭*。若要執行此作業，請切換 `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` 屬性現在會包含五個元素，順序如下：`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`)，讓它包含五個元素：  
+ `[0]`—`Chisel`
+ `[1]`—`Hammer`
+ `[2]`—`Nails`
+ `[3]`—`Screwdriver`
+ `[4]`—`Hacksaw`
下列 AWS Command Line Interface (AWS CLI) 範例`Nails`會從清單中刪除 `Hammer`和 。  

```
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` 或集合資料類型。
+ *value* 元素是您要新增至屬性的數字 (針對 `Number` 資料類型)，或要附加至屬性的集合 (針對集合類型)。

```
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* 元素是屬性的文件路徑。屬性必須是集合資料類型。
+ *subset* 是您要從 *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 動作。此操作會將「釘子」新增到 `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 SDKs程式設計](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>

在以下語法摘要中，*operand* 可以是以下項目：
+ 最上層屬性名稱，例如 `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>

使用下列函數可判斷項目中是否具有某屬性，或評估某屬性的值。這些函數名稱區分大小寫。針對巢狀屬性，您必須提供其完整文件路徑。


****  

| 函式 | Description | 
| --- | --- | 
|  `attribute_exists (path)`  | 如果項目包含 `path` 指定的屬性，則為 true。 範例：檢查 `Product` 資料表中的項目是否具有側視圖。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/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_tw/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_tw/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_tw/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_tw/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_tw/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_tw/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) 表達式屬性值 `:v_sub` 是 `Company` 的預留位置。 範例：檢查產品是否提供紅色款式。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/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_tw/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  如果屬性的類型為 `Binary`，`size` 會傳回屬性值中的位元組數目。 範例：假設 `ProductCatalog` 項目具有名為 `VideoClip` 的二進制屬性，其中包含使用中產品的短片。以下表達式會檢查 `VideoClip` 是否超過 64,000 個位元組。表達式屬性值 `:v_sub` 是 `64000` 的預留位置。[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/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_tw/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_tw/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) 範例。這些範例是以 [在 DynamoDB 中使用表達式時參考項目屬性](Expressions.Attributes.md) 中引進的 `ProductCatalog` 資料表為基礎。此資料表的分割區索引鍵是 `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)` AND `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 會傳回以下錯誤訊息：The conditional request failed (條件式請求失敗)。

**注意**  
如需 `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，則操作會成功；否則，操作會失敗。

只有在產品沒有 `Price` 屬性時，以下範例才會使用 `attribute_not_exists` 來刪除產品。

```
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，則操作會成功；否則，操作會失敗。

下列範例只有在具有字串集合類型的 `Color` 屬性的情況下，才會使用 `attribute_type` 刪除產品。

```
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，則操作會成功；否則，操作會失敗。

只有在 `Color` 字串集合具有含特定值的元素時，下列範例才會使用 `contains` 刪除產品。

```
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，則操作會成功；否則，操作會失敗。

只有在 `VideoClip` 二進制屬性大於 `64000` 位元組時，下列範例才會使用 `size` 刪除產品。

```
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 過期時間戳記。時間戳記必須以秒精細程度以 [Unix epoch 時間格式](https://en.wikipedia.org/wiki/Unix_time)儲存為[數字](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes)資料類型。TTL 程序會忽略 TTL 屬性不是數字類型的項目。每次建立或更新項目時，您可計算其過期時間，並將結果儲存在 TTL 屬性中。

具有有效且已過期 TTL 屬性的項目，可能會在過期後數天內由系統自動刪除。您仍可更新尚未刪除的過期項目，例如變更或移除其 TTL 屬性。在更新過期項目時，建議使用條件運算式，以確保該項目未在此期間被刪除。使用篩選運算式，從[掃描](Scan.md#Scan.FilterExpression)與[查詢](Query.FilterExpression.md)結果中排除過期項目。

被刪除的項目運作方式與一般刪除操作所刪除的項目相同。項目刪除後，會以「服務刪除」的形式送入 DynamoDB Streams，而非「使用者刪除」，並會從本機次要索引與全域次要索引中移除，與其他刪除操作相同。

如果您使用 [Global Tables version 2019.11.21 (目前版本)](GlobalTables.md)，且同時啟用 TTL 功能，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) 中啟用 TTL，或使用 [Amazon DynamoDB API 參考](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/)與任何支援的 AWS SDKs。在所有分割區啟用 TTL 約需一小時。

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

1. 登入 AWS 管理主控台 ，並在 https：//[https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/) 開啟 DynamoDB 主控台。

1. 選擇 **Tables (資料表)**，然後選擇您想要修改的資料表。

1. 在**附加設定**分頁的**存留時間 (TTL)**區段中，選取**開啟**以啟用 TTL。

1. 在資料表上啟用 TTL 時，DynamoDB 會要求您識別服務在判斷項目是否符合過期資格時將尋找的特定屬性名稱。如下所示的 TTL 屬性名稱區分大小寫，且必須與讀寫操作中定義的屬性一致。若不一致，過期項目將無法被刪除。若要重新命名 TTL 屬性，您必須先停用 TTL，然後使用新的屬性名稱重新啟用。停用後，TTL 仍會在約 30 分鐘內持續處理刪除作業。還原資料表後，必須重新設定 TTL。  
![\[DynamoDB 用於判定項目是否符合過期條件的區分大小寫 TTL 屬性名稱。\]](http://docs.aws.amazon.com/zh_tw/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 及 AWS CLI，將項目新增至已設定存留時間屬性的 `TTLExample` 資料表。

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

此範例建立的過期時間為從目前的日期開始加 5 天。然後，將過期時間轉換成 Epoch 時間格式，最終將項目新增到 "`TTLExample`" 表。

**注意**  
 設定存留時間過期數值的其中一種方式，是計算要新增到過期時間的秒數。例如，5 天等於 432,000 秒。但是通常建議從日期開始操作。

取得目前時間的 Epoch 時間格式非常容易，如以下範例所示。
+ Linux 終端機：`date +%s`
+ Python：`import time; int(time.time())`
+ Java：`System.currentTimeMillis() / 1000L`
+ JavaScript：`Math.floor(Date.now() / 1000)`

## 使用 啟用 DynamoDB TTL CloudFormation
<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 天。

計算出的過期時間必須採用 epoch 格式 (以秒為單位)。要符合過期與刪除條件，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 天。接著，將時間轉換為 epoch 格式，並以整數型別儲存在 TTL 屬性中。

下列程式碼範例示範如何建立含有 TTL 的項目。

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

**適用於 Java 2.x 的 SDK**  

```
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 參考*》中的 [PutItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/PutItem)。

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

**適用於 JavaScript (v3) 的 SDK**  

```
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 參考*》中的 [PutItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/PutItemCommand)。

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

**適用於 Python (Boto3) 的 SDK**  

```
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 的詳細資訊，請參閱《*適用於 Python (Boto3) 的AWS SDK API 參考*》中的 [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 2.x 的 SDK**  
更新資料表中現有 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 參考](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateItem)》中的 *UpdateItem*。

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

**適用於 JavaScript (v3) 的 SDK**  

```
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 參考](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/UpdateItemCommand)》中的 *UpdateItem*。

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

**適用於 Python (Boto3) 的 SDK**  

```
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 的詳細資訊，請參閱《*適用於 Python (Boto3) 的AWS SDK API 參考*》中的 [UpdateItem](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/UpdateItem)。

------

本介紹中的 TTL 範例示範了一種方法，可確保僅保留最近更新的項目於資料表中。更新的項目其存留期會延長，而建立後未更新的項目將在到期後自動刪除，不產生額外成本，有助於減少儲存並維持資料表整潔。

# 操作過期項目與存留時間 (TTL)
<a name="ttl-expired-items"></a>

可從讀取與寫入操作中篩選出待刪除的過期項目。當過期資料已失效且不應再使用時，這項設計特別實用。若未進行篩選，這些項目將持續出現在讀取與寫入操作中，直到由背景程序刪除。

**注意**  
在刪除前，這些項目仍計入儲存與讀取成本。

TTL 刪除可在 DynamoDB 串流中識別，但僅限於刪除發生的區域。被複寫至全域資料表其他區域的 TTL 刪除，無法在那些區域的 DynamoDB 串流中識別。

## 從讀取操作中篩選過期項目
<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` 以符合 epoch 時間格式。

下列程式碼範例示範如何查詢 TTL 項目。

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

**適用於 Java 2.x 的 SDK**  
查詢篩選表達式，以使用 在 DynamoDB 資料表中收集 TTL 項目 AWS SDK for Java 2.x。  

```
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 參考*》中的 [Query](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/Query)。

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

**適用於 JavaScript (v3) 的 SDK**  
查詢篩選表達式，以使用 在 DynamoDB 資料表中收集 TTL 項目 適用於 JavaScript 的 AWS SDK。  

```
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 參考*》中的 [Query](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/QueryCommand)。

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

**適用於 Python 的 SDK (Boto3)**  
查詢篩選表達式，以使用 在 DynamoDB 資料表中收集 TTL 項目 適用於 Python (Boto3) 的 AWS SDK。  

```
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 的詳細資訊，請參閱《*適用於 Python (Boto3) 的AWS SDK API 參考*》中的 [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 2.x 的 SDK**  
使用條件更新資料表中現有的 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 參考](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateItem)》中的 *UpdateItem*。

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

**適用於 JavaScript (v3) 的 SDK**  
使用條件更新資料表中現有的 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 參考](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/UpdateItemCommand)》中的 *UpdateItem*。

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

**適用於 Python (Boto3) 的 SDK**  
使用條件更新資料表中現有的 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 的詳細資訊，請參閱《*適用於 Python (Boto3) 的AWS SDK API 參考*》中的 [UpdateItem](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/UpdateItem)。

------

## 在 DynamoDB 串流中識別已刪除的項目
<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` 值的項目，因為 `KeyConditionExpression` 中不包含排序索引鍵 (`Subject`)。  

```
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 範例會查詢特定 `ForumName`（分割區索引鍵） 和 `Subject`（排序索引鍵） 的`Thread`資料表。在找到的項目中，只會傳回最受歡迎的討論主題：換句話說，只會傳回具有超過一定 `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` 值，並用它做為新 `Query` 要求的 `ExclusiveStartKey` 參數。

1. 執行新的 `Query` 請求。

1. 前往步驟 1。

換句話說，`LastEvaluatedKey` 回應的 `Query` 應做為下一個 `ExclusiveStartKey` 請求的 `Query` 使用。若 `LastEvaluatedKey` 回應中沒有 `Query` 元素，表示您已擷取到結果的最終頁。如果 `LastEvaluatedKey` 不是空的，則不一定意味著結果集中有更多資料。檢查 `LastEvaluatedKey` 是否為空，是確定您是否已到達結果集末頁的唯一方式。

您可以使用 AWS CLI 來檢視此行為。會重複 AWS CLI 傳送低階`Query`請求至 DynamoDB，直到結果`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 然後， 向 DynamoDB 發出另一個`Query`請求。此請求和回應模式會持續到最終回應出現為止。

```
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 SDKs 會處理低階 DynamoDB 回應 （包括是否存在 `LastEvaluatedKey`)，並提供用於分頁`Query`結果的各種抽象概念。例如，適用於 Java 的開發套件文件介面會提供 `java.util.Iterator` 支援，讓您可一次處理一個結果。  
如需各種程式設計語言的程式碼範例，請參閱《[Amazon DynamoDB 入門指南](https://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/)》和所需語言的 AWS 軟體開發套件文件。

您還可以透過限制結果集的項目數 (使用 `Query` 操作的 `Limit` 參數) 來減少頁面大小。

如需使用 DynamoDB 進行查詢的詳細資訊，請參閱 [在 DynamoDB 中查詢資料表](Query.md)。

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

本節涵蓋 DynamoDB 查詢操作的其他層面，包括限制結果大小、計算掃描項目與傳回項目、監控讀取容量耗用量，以及控制讀取一致性。

## 限制結果集的項目數
<a name="Query.Limit"></a>

您可以使用 `Query` 操作來限制其讀取的項目數。若要執行此作業，請將 `Limit` 參數設為您希望的最大項目數。

例如，假設您 `Query` 一份資料表，將 `Limit` 值設為 `6` 且不使用篩選條件表達式。`Query` 結果會包含資料表中符合請求索引鍵條件表達式的前六個項目。

現在假設您在 `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` 回應都包含經該特定 `Query` 請求處理過的項目 `ScannedCount` 和 `Count`。若要取得所有 `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` 結果會包含資料表中的前六個項目。

現在假設您在 `Scan` 中新增一個篩選條件表達式。在本案例中，DynamoDB 會將篩選條件表達式套用至傳回的六個項目，捨棄那些不符的項目。最終的 `Scan` 結果會包含 6 個或以下項目，視篩選的項目數而定。

## 為結果編製分頁
<a name="Scan.Pagination"></a>

DynamoDB 會對 `Scan` 操作的結果進行*分頁*。透過編製分頁，`Scan` 結果會分成數個大小為 1 MB (或更小) 的資料「頁」。應用程式可以處理結果的第一頁、第二頁，以此類推。

單一 `Scan` 只會傳回符合 1 MB 大小限制的結果集。

為判斷是否有更多結果，並且一次擷取一頁結果，應用程式應執行下列作業：

1. 檢查低層級 `Scan` 結果：
   + 若結果包含 `LastEvaluatedKey` 元素，請接著進行步驟 2。
   + 若結果中*沒有* `LastEvaluatedKey`，就表示再也沒有要擷取的項目。

1. 建構新的 `Scan` 請求，和前一個請求使用相同的參數。但這一次採用步驟 1 的 `LastEvaluatedKey` 值，並用它做為新 `Scan` 要求的 `ExclusiveStartKey` 參數。

1. 執行新的 `Scan` 請求。

1. 前往步驟 1。

換句話說，`LastEvaluatedKey` 回應的 `Scan` 應做為下一個 `ExclusiveStartKey` 請求的 `Scan` 使用。若 `Scan` 回應中沒有 `LastEvaluatedKey` 元素，表示您已擷取到結果的最終頁。(檢查是否沒有 `LastEvaluatedKey` 是確定您是否已到達結果集末頁的唯一方式)。

您可以使用 AWS CLI 來檢視此行為。會重複 AWS CLI 傳送低階`Scan`請求至 DynamoDB，直到結果`LastEvaluatedKey`中不再出現 為止。請考慮下列掃描整個`Movies`資料表，但僅傳回特定類型電影 AWS CLI 的範例。

```
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 然後， 向 DynamoDB 發出另一個`Scan`請求。此請求和回應模式會持續到最終回應出現為止。

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

若沒有 `LastEvaluatedKey`，就表示已不再有要擷取的項目。

**注意**  
 AWS SDKs 會處理低階 DynamoDB 回應 （包括是否存在 `LastEvaluatedKey`)，並提供用於分頁`Scan`結果的各種抽象概念。例如，適用於 Java 的開發套件文件介面會提供 `java.util.Iterator` 支援，讓您可一次處理一個結果。  
如需各種程式設計語言的程式碼範例，請參閱《[Amazon DynamoDB 入門指南](https://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/)》和所需語言的 AWS 軟體開發套件文件。

## 計算結果中的項目
<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` 回應都包含經該特定 `Scan` 請求處理過的項目 `ScannedCount` 和 `Count`。若要取得所有 `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)，在資料表備份或複寫案例中很實用。首先使用 `ConsistentRead` 設為 true 的 `Scan`，取得和資料表資料一致的副本。在 `Scan` 期間，DynamoDB Streams 會紀錄資料表發生的所有額外寫入活動。`Scan` 完成後，您可將串流的寫入活動套用至資料表。

**注意**  
與將 `ConsistentRead` 保留預設值 (`false`) 相較，將 `ConsistentRead` 設成 `true` 的 `Scan` 操作會使用兩倍的讀取容量單位。

## 平行掃描
<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_tw/amazondynamodb/latest/developerguide/images/ParallelScan.png)




在此圖中，應用程式產生三個執行緒，並為每個執行緒指派一個數字。(區段從零開始，所以第一個數字永遠為 0。) 每個執行緒都會發出 `Scan` 請求、將 `Segment` 設定為指定號碼，並將 `TotalSegments` 設定為 3。每個執行緒都會掃描其指定的區段，一次擷取 1 MB 的資料，並將資料傳回至應用程式的主執行緒。

DynamoDB 透過將雜湊函數套用至每個項目的分割區索引鍵，將項目指派給*區段*。對於指定的`TotalSegments`值，具有相同分割區索引鍵的所有項目一律會指派給相同的 `Segment`。這表示在*項目 1*、*項目 2* 和*項目 3* 全部共用 `pk="account#123"`（但具有不同的排序索引鍵） 的表格中，這些項目將由相同的工作者處理，無論排序索引鍵值或*項目集合*的大小為何。

由於*區段*指派僅以分割區索引鍵雜湊為基礎，因此區段可能分佈不均勻。某些區段可能不包含任何項目，而其他區段則可能包含具有大型項目集合的許多分割區索引鍵。因此，增加區段總數並不能保證更快的掃描效能，特別是當分割區索引鍵未均勻分佈到金鑰空間時。

`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 Command Line Interface，並使用 PartiQL 的 AWS 管理主控台、NoSQL Workbench 和 DynamoDB APIs 執行臨機操作查詢。

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 規範和核心查詢語言的教學課程，請參閱 [PartiQL 文件](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
+ The AWS Command Line Interface (AWS CLI)
+ DynamoDB API

如需使用這些方法存取 DynamoDB 的相關資訊，請參閱[存取 DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AccessingDynamoDB.html)。

# DynamoDB 專用 PartiQL 入門
<a name="ql-gettingstarted"></a>

本節說明如何從 Amazon DynamoDB 主控台、 AWS Command Line Interface (AWS CLI) 和 DynamoDB API 使用 DynamoDB 專用 PartiQL。

在下列範例中，[DynamoDB 入門](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStartedDynamoDB.html)教學課程中所定義的 DynamoDB 資料表是先決條件。

如需有關使用 DynamoDB 主控台 AWS Command Line Interface或 DynamoDB APIs 存取 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) 來建置 [DynamoDB 專用 PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html) 陳述式，請選擇位於 NoSQL Workbench for DynamoDB [Operation Builder](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.querybuilder.operationbuilder.html) 右上角的 **PartiQL operations** (PartiQL 操作)。

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

![\[PartiQL 編輯器介面，顯示在 Music 資料表上執行查詢操作的結果。\]](http://docs.aws.amazon.com/zh_tw/amazondynamodb/latest/developerguide/images/partiqlgettingstarted.png)


1. 登入 AWS 管理主控台 ，並在 https：//[https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/) 開啟 DynamoDB 主控台。

1. 在主控台左側的導覽窗格中，選擇 **PartiQL editor** (PartiQL 編輯器)。

1. 選擇 **Music** (音樂) 資料表。

1. 選擇 **Query table** (查詢資料表)。此動作會產生不會導致完整資料表掃描的查詢。

1. 使用字串值 `Acme Band` 取代 `partitionKeyValue`。使用字串值 `Happy Day` 取代 `sortKeyValue`。

1. 選擇 **Run** (執行) 按鈕。

1. 您可以選擇 **Table view** (資料表檢視) 或 **JSON view** (JSON 檢視) 按鈕來檢視查詢的結果。

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

![\[NoSQL Workbench 介面。它會顯示 PartiQL SELECT 陳述式，您可以在 Music 資料表上執行。\]](http://docs.aws.amazon.com/zh_tw/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. 使用 UPDATE 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. 使用刪除 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>

下表列出您可搭配 DynamoDB 專用 PartiQL 使用的資料類型。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/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)。

# 適用於 DynamoDB 的 PartiQL 陳述式
<a name="ql-reference.statements"></a>

Amazon DynamoDB 支援下列 PartiQL 陳述式。

**注意**  
DynamoDB 不支援所有 PartiQL 陳述式。  
此參考提供使用 AWS CLI 或 APIs 手動執行之 PartiQL 陳述式的基本語法和使用範例。

*資料操作語言* (DML) 是一組用來管理 DynamoDB 資料表中資料的 PartiQL 陳述式。您可使用 DML 陳述式新增、修改或刪除資料表中的資料。

支援下列 DML 和查詢語言陳述式：
+ [適用於 DynamoDB 的 PartiQL Select 陳述式](ql-reference.select.md)
+ [適用於 DynamoDB 的 PartiQL Update 陳述式](ql-reference.update.md)
+ [適用於 DynamoDB 的 PartiQL Insert 陳述式](ql-reference.insert.md)
+ [適用於 DynamoDB 的 PartiQL Delete 陳述式](ql-reference.delete.md)

DynamoDB 專用 PartiQL 亦支援 [使用 DynamoDB 專用 PartiQL 執行交易](ql-reference.multiplestatements.transactions.md) 和 [使用 DynamoDB 專用 PartiQL 執行批次操作](ql-reference.multiplestatements.batching.md)。

# 適用於 DynamoDB 的 PartiQL Select 陳述式
<a name="ql-reference.select"></a>

在 Amazon DynamoDB 中，使用 `SELECT` 陳述式從資料表檢索資料。

如果 WHERE 子句中未提供與分割區索引鍵相等或 IN 條件，使用 `SELECT` 陳述式可能會導致完整的資料表掃描。掃描操作會檢查每個項目的要求值，並可能會在單一操作中耗用大型資料表或索引的佈建輸送量。

如果您想避免在 PartiQL 中進行完整的資料表掃描，則可以：
+ 確保 [WHERE 子句條件](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.select.html#ql-reference.select.parameters)會據此進行相應設定，撰寫您的 `SELECT` 陳述式便不會導致完整的資料表掃描。
+ 請使用《DynamoDB 開發人員指南》中 [範例：允許在 DynamoDB 專用 PartiQL 中執行選取陳述式並拒絕完整的資料表掃描陳述式](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)
+ [Parameters](#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] , ...]
```

## Parameters
<a name="ql-reference.select.parameters"></a>

***表達式***  
(必要) 從 `*` 萬用字元形成的投影，或來自結果集中一或多個屬性名稱或文件路徑的投影清單。一個表達式可以包含對 [搭配 DynamoDB 使用 PartiQL 函數](ql-functions.md) 的呼叫或由 [適用於 DynamoDB 的 PartiQL 算術、比較和邏輯運算子](ql-operators.md) 修改的欄位。

***資料表***  
(必要) 要查詢的資料表名稱。

***索引***  
(選用) 要查詢的索引名稱。  
查詢索引時，必須在資料表名稱和索引名稱上加上雙引號。  

```
SELECT * 
FROM "TableName"."IndexName"
```

***condition***  
(選用) 查詢的選取條件。  
若要確保 `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
```

下列查詢會針對具有特定分割區索引鍵、`OrderID` 和值的 `Orders` 資料表，使用 OR 運算子傳回其中的所有項目。

```
SELECT OrderID, Total
FROM "Orders"
WHERE OrderID = 1 OR OrderID = 2
```

下列查詢會針對具有特定分割區索引鍵、`OrderID` 和值的 `Orders` 資料表，使用 IN 運算子傳回其中的所有項目。傳回的結果會根據 `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` 之特定 `Total` 順序範圍內 `Orders` 資料表中的所有項目。

```
SELECT OrderID, Total 
FROM "Orders"
WHERE Total IN [500, 600]
```

下列查詢顯示完整的資料表掃描，該掃描會傳回使用 BETWEEN 運算子和非索引鍵屬性 `Total` 之特定 `Total` 順序範圍內 `Orders` 資料表中的所有項目。

```
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 子句條件中的文件路徑傳回在 2019 年 12 月 24 日之後首次使用 FireStick 裝置的項目清單。

```
SELECT Devices 
FROM WatchList 
WHERE Devices.FireStick.DateWatched[0] >= '12/24/19'
```

# 適用於 DynamoDB 的 PartiQL Update 陳述式
<a name="ql-reference.update"></a>

使用 `UPDATE` 陳述式來修改 Amazon DynamoDB 資料表中項目內一或多個屬性的值。

**注意**  
您一次只能更新一個項目，因為您無法發出可刪除多個項目的單個 DynamoDB PartiQL 陳述式。如需更新多個項目的相關資訊，請參閱 [使用 DynamoDB 專用 PartiQL 執行交易](ql-reference.multiplestatements.transactions.md) 或 [使用 DynamoDB 專用 PartiQL 執行批次操作](ql-reference.multiplestatements.batching.md)。

**Topics**
+ [語法](#ql-reference.update.syntax)
+ [Parameters](#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] *
```

## Parameters
<a name="ql-reference.update.parameters"></a>

***資料表***  
(必要) 包含要修改之資料的資料表。

***路徑***  
(必要) 要建立或修改的屬性名稱或文件路徑。

***資料***  
(必要) 屬性值或操作的結果。  
與 SET 搭配使用的支援操作：  
+ LIST\$1APPEND：將數值新增至清單類型。
+ SET\$1ADD：將數值新增至數字或字串集。
+ SET\$1DELETE：從數字或字串集中刪除數值。

***condition***  
(必要) 要修改之項目的選取條件。此條件必須解析為單一主索引鍵值。

***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>

更新現有項目中的屬性值。如果屬性不存在，則會建立此屬性。

下列查詢會透過新增數字類型的屬性 (`AwardsWon`) 和映射類型的屬性 (`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'
```

# 適用於 DynamoDB 的 PartiQL Delete 陳述式
<a name="ql-reference.delete"></a>

使用 `DELETE` 陳述式從您的 Amazon DynamoDB 資料表中刪除現有項目。

**注意**  
您一次只能刪除一個項目。您無法發出可刪除多個項目的單個 DynamoDB PartiQL 陳述式。如需刪除多個項目的相關資訊，請參閱 [使用 DynamoDB 專用 PartiQL 執行交易](ql-reference.multiplestatements.transactions.md) 或 [使用 DynamoDB 專用 PartiQL 執行批次操作](ql-reference.multiplestatements.batching.md)。

**Topics**
+ [語法](#ql-reference.delete.syntax)
+ [Parameters](#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 *
```

## Parameters
<a name="ql-reference.delete.parameters"></a>

***資料表***  
(必要) 包含要刪除之項目的 DynamoDB 資料表。

***condition***  
(必要) 要刪除之項目的選取條件；此條件必須解析為單一主索引鍵值。

***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"
            }
        }
    ]
}
```

# 適用於 DynamoDB 的 PartiQL Insert 陳述式
<a name="ql-reference.insert"></a>

使用 `INSERT` 陳述式在 Amazon DynamoDB 中將項目新增至資料表。

**注意**  
您一次只能插入一個項目，因為您無法發出可插入多個項目的單個 DynamoDB PartiQL 陳述式。如需插入多個項目的相關資訊，請參閱 [使用 DynamoDB 專用 PartiQL 執行交易](ql-reference.multiplestatements.transactions.md) 或 [使用 DynamoDB 專用 PartiQL 執行批次操作](ql-reference.multiplestatements.batching.md)。

**Topics**
+ [語法](#ql-reference.insert.syntax)
+ [Parameters](#ql-reference.insert.parameters)
+ [傳回值](#ql-reference.insert.return)
+ [範例](#ql-reference.insert.examples)

## 語法
<a name="ql-reference.insert.syntax"></a>

插入單一項目。

```
INSERT INTO table VALUE item
```

## Parameters
<a name="ql-reference.insert.parameters"></a>

***資料表***  
(必要) 您要插入資料的資料表。索資料表必須已存在。

***項目***  
(必要) 有效的 DynamoDB 項目表示為 [PartiQL 元組](https://partiql.org/docs.html)。您必須在 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'}
```

# 搭配 DynamoDB 使用 PartiQL 函數
<a name="ql-functions"></a>

Amazon DynamoDB 中的 PartiQL 支援下列 SQL 標準函數的內建變體。

**注意**  
DynamoDB 目前不支援任何未包含在此清單中的 SQL 函數。

## 彙總函數
<a name="ql-functions.aggregate"></a>
+ [搭配 Amazon DynamoDB 專用 PartiQL 使用 SIZE 函數](ql-functions.size.md)

## 條件函數
<a name="ql-functions.conditional"></a>
+ [搭配 DynamoDB 專用 PartiQL 使用 EXISTS 函數](ql-functions.exists.md)
+ [搭配 DynamoDB 專用 PartiQL 使用 ATTRIBUTE\$1TYPE 函數](ql-functions.attribute_type.md)
+ [搭配 DynamoDB 專用 PartiQL 使用 BEGINS\$1WITH 函數](ql-functions.beginswith.md)
+ [搭配 DynamoDB 專用 PartiQL 使用 CONTAINS 函數](ql-functions.contains.md)
+ [搭配 DynamoDB 專用 PartiQL 使用 MISSING 函數](ql-functions.missing.md)

# 搭配 DynamoDB 專用 PartiQL 使用 EXISTS 函數
<a name="ql-functions.exists"></a>

您可以使用 EXISTS 來執行與 `ConditionCheck` 會在 [TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems) API 中執行的相同函數。EXISTS 函數只能在交易中使用。

給定一個值，如果該值是一個非空集合，則傳回 `TRUE`。如果不是，則傳回 `FALSE`。

**注意**  
此函數只能在交易操作中使用。

## 語法
<a name="ql-functions.exists.syntax"></a>

```
EXISTS ( statement )
```

## 引數
<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')
```

# 搭配 DynamoDB 專用 PartiQL 使用 BEGINS\$1WITH 函數
<a name="ql-functions.beginswith"></a>

如果指定的屬性以特定子字串開頭，則傳回 `TRUE`。

## 語法
<a name="ql-functions.beginswith.syntax"></a>

```
begins_with(path, value )
```

## 引數
<a name="ql-functions.beginswith.arguments"></a>

*路徑*  
(必要) 要使用的屬性名稱或文件路徑。

*值*  
(必要) 要搜尋的字串。

## 傳回類型
<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')
```

# 搭配 DynamoDB 專用 PartiQL 使用 MISSING 函數
<a name="ql-functions.missing"></a>

如果項目不包含指定的屬性，即傳回 `TRUE`。只有等於和不等於運算子可以與此函數一起使用。

## 語法
<a name="ql-functions.missing.syntax"></a>

```
 attributename IS | IS NOT  MISSING 
```

## 引數
<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
```

# 搭配 DynamoDB 專用 PartiQL 使用 ATTRIBUTE\$1TYPE 函數
<a name="ql-functions.attribute_type"></a>

如果指定路徑的屬性是特定資料類型，則傳回 `TRUE`。

## 語法
<a name="ql-functions.attribute_type.syntax"></a>

```
attribute_type( attributename, type )
```

## 引數
<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')
```

# 搭配 DynamoDB 專用 PartiQL 使用 CONTAINS 函數
<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 )
```

## 引數
<a name="ql-functions.contains.arguments"></a>

*路徑*  
(必要) 要使用的屬性名稱或文件路徑。

*子字串*  
(必要) 要檢查的屬性子字串或集合成員。如需詳細資訊，請參閱 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')
```

# 搭配 Amazon DynamoDB 專用 PartiQL 使用 SIZE 函數
<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)
```

## 引數
<a name="ql-functions.size.arguments"></a>

*路徑*  
(必要) 屬性名稱或文件路徑。  
如需了解支援的類型，請參閱 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>


****  

| 運算子 | Description | 
| --- | --- | 
| \$1 | 加 | 
| - | 減 | 

## 比較運算子
<a name="ql-operators.comparison"></a>


****  

| 運算子 | Description | 
| --- | --- | 
| = | 等於 | 
| <> | 不等於 | 
| \$1= | 不等於 | 
| > | Greater than | 
| < | Less than | 
| >= | 大於或等於 | 
| <= | 小於或等於 | 

## 邏輯運算子
<a name="ql-operators.logical"></a>


****  

| 運算子 | Description | 
| --- | --- | 
| AND | 如果以 AND 分隔的所有的條件為 TRUE，則為 TRUE | 
| BETWEEN |  如果運算元在比較範圍內，則為 `TRUE`。 此運算子包含您套用運算元的下限和上限。  | 
| IN | `TRUE` 如果運算元等於表達式清單之一 （上限為 50 個雜湊屬性值或上限為 100 個非索引鍵屬性值）。 結果會以最多 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)。

# 使用 DynamoDB 專用 PartiQL 執行交易
<a name="ql-reference.multiplestatements.transactions"></a>

本節說明如何搭配 DynamoDB 專用 PartiQL 使用交易。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)
+ [Parameters](#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 "
         }, ...]
   } , ...
]
```

## Parameters
<a name="ql-reference.multiplestatements.transactions.parameters"></a>

***陳述式***  
(必要) DynamoDB 專用 PartiQL 支援的陳述式。  
整個交易必須由讀取陳述式或寫入陳述式所組成。你不能在一個交易中混合兩者。

***parametertype***  
(選用) DynamoDB 類型，如果在指定 PartiQL 陳述式時使用了參數。

***parametervalue***  
(選用) 參數值，如果在指定 PartiQL 陳述式時使用了參數。

## 傳回值
<a name="ql-reference.multiplestatements.transactions.return"></a>

此陳述式不會傳回寫入作業 (插入、更新或刪除) 的任何值。但是，它根據 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
           {}
       ]
   }
   ```

------

# 使用 DynamoDB 專用 PartiQL 執行批次操作
<a name="ql-reference.multiplestatements.batching"></a>

本節說明如何搭配 DynamoDB 專用 PartiQL 使用批次陳述式。

**注意**  
整個批次必須由讀取陳述式或寫入陳述式所組成；一個批次中不能同時出現這兩種陳述式樣。
`BatchExecuteStatement` 和 `BatchWriteItem` 每個批次不可以執行超過 25 條陳述式。
`BatchExecuteStatement` 會使用 `BatchGetItem`，其會取得個別陳述式中主索引鍵的清單。

**Topics**
+ [語法](#ql-reference.multiplestatements.batching.syntax)
+ [Parameters](#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 "
         }, ...]
   } , ...
]
```

## Parameters
<a name="ql-reference.multiplestatements.batching.parameters"></a>

***陳述式***  
(必要) DynamoDB 專用 PartiQL 支援的陳述式。  
+ 整個批次必須由讀取陳述式或寫入陳述式所組成；一個批次中不能同時出現這兩種陳述式樣。
+ `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());
        }
    }

}
```

------

# DynamoDB 專用 PartiQL 的 IAM 安全政策
<a name="ql-iam"></a>

需要以下許可：
+ 若要使用 DynamoDB 專用 PartiQL 讀取項目，您必須擁有資料表或索引的 `dynamodb:PartiQLSelect` 許可。
+ 若要使用 DynamoDB 專用 PartiQL 插入項目，您必須擁有資料表或索引的 `dynamodb:PartiQLInsert` 許可。
+ 若要使用 DynamoDB 專用 PartiQL 更新項目，您必須擁有資料表或索引的 `dynamodb:PartiQLUpdate` 許可。
+ 若要使用 DynamoDB 專用 PartiQL 刪除項目，您必須擁有資料表或索引的 `dynamodb:PartiQLDelete` 許可。

## 範例：允許在資料表上執行所有 DynamoDB 專用 PartiQL 陳述式 (選取/插入/更新/刪除)
<a name="access-policy-ql-iam-example1"></a>

下列 IAM 政策會授予許可，允許在資料表上執行所有 DynamoDB 專用 PartiQL 陳述式。

------
#### [ 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"
         ]
      }
   ]
}
```

------

## 範例：允許在資料表上執行 DynamoDB 專用 PartiQL 選取陳述式
<a name="access-policy-ql-iam-example2"></a>

下列 IAM 政策會授予許可，允許在特定資料表上執行 `select` 陳述式。

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ]
      }
   ]
}
```

------

## 範例：允許在索引上執行 DynamoDB 專用 PartiQL 插入陳述式
<a name="access-policy-ql-iam-example3"></a>

下列 IAM 政策會授予許可，允許在特定索引上執行 `insert` 陳述式。

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLInsert"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music/index/index1"
         ]
      }
   ]
}
```

------

## 範例：允許在資料表上僅執行 DynamoDB 專用 PartiQL 交易陳述式
<a name="access-policy-ql-iam-example4"></a>

下列 IAM 政策會授予許可，允許僅在特定資料表上執行交易陳述式。

------
#### [ 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"
               ]
            }
         }
      }
   ]
}
```

------

## 範例：允許在資料表上執行 DynamoDB 專用 PartiQL 非交易式讀取和寫入，並封鎖 PartiQL 交易式讀取和寫入交易陳述式。
<a name="access-policy-ql-iam-example5"></a>

 下列 IAM 政策會授予許可，允許執行 DynamoDB 專用 PartiQL 非交易式讀取和寫入，同時封鎖 DynamoDB 專用 PartiQL 交易式讀取和寫入。

------
#### [ 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"
         ]
      }
   ]
}
```

------

## 範例：允許在 DynamoDB 專用 PartiQL 中執行選取陳述式並拒絕完整的資料表掃描陳述式
<a name="access-policy-ql-iam-example6"></a>

下列 IAM 政策會授予許可，允許在特定資料表上執行 `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) 操作。

**注意**  
適用於 Java 的開發套件也提供物件持久性模型，讓您將用戶端類別映射至 DynamoDB 資料表。此方法可以減少您必須撰寫的程式碼數量。如需詳細資訊，請參閱 [Java 1.x：DynamoDBMapper](DynamoDBMapper.md)。

本節包含 Java 範例，執行數個 Java 文件 API 項目動作及數個完整的工作範例。

**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 資料表中。若要執行此作業，請使用 `Item` 的 `withJSON` 方法。此方法會剖析 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` 表，放在名為 `VendorInfo` 的 `Map` 屬性中。下列 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) 一節中，您將 JSON 文件存放在名為 `VendorInfo` 的 `Map` 屬性中。您可以使用 `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`。您如此即可指定要從資料表擷取的屬性。

下列程式碼範例會從 `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` 屬性。它也會將價格減一。

`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`，指出只有當書籍不再出版時 (`InPublication` 屬性為 false)，才能刪除 `ProductCatalog` 中的書籍項目。

**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 操作。此範例會建立項目、擷取該項目、執行數次更新，最後刪除該項目。

**注意**  
適用於 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>

本節提供使用 適用於 Java 的 AWS SDK 文件 API 在 Amazon DynamoDB 中批次寫入和批次取得操作的範例。

**注意**  
適用於 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 中建立資料表，以及載入程式碼範例的資料](SampleData.md) 一節的說明將資料載入 DynamoDB 的帳戶。  
如需執行下列範例的逐步說明，請參閱「[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` 類別進行解壓縮。

**注意**  
適用於 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` 用戶端提供 CRUD 操作的 `PutItem`、`GetItem`、`UpdateItem` 和 `DeleteItem` 方法。

**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 軟體開發套件 API 上傳項目的步驟：

1. 建立 `AmazonDynamoDBClient` 類別的執行個體。

1. 您可以透過建立 `PutItemRequest` 類別的執行個體來提供必要的參數。

   若要放入項目，您必須提供資料表名稱及項目。

1. 提供您在前一個步驟中建立的 `PutItem` 物件來執行 `PutItemRequest` 方法。

下列 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. 提供您在前一個步驟中建立的 `GetItem` 物件來執行 `GetItemRequest` 方法。

下列 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 軟體開發套件 API 來更新現有項目的步驟。

1. 建立 `AmazonDynamoDBClient` 類別的執行個體。

1. 您可以透過建立 `UpdateItemRequest` 類別的執行個體來提供必要的參數。

   這是您說明所有更新的請求物件，例如新增屬性、更新現有的屬性或刪除屬性。若要刪除現有的屬性，請以 Null 值指定屬性名稱。

1. 提供您在前一個步驟中建立的 `UpdateItem` 物件來執行 `UpdateItemRequest` 方法。

下列 C\$1 程式碼範例示範前述步驟。範例會更新 `ProductCatalog` 表中的項目。它會將新的作者新增到 `Authors` 集合，並刪除現有的 `ISBN` 屬性。它也會將價格減一。



```
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` 來實作原子計數器以增加或減少現有屬性的值，卻不干擾其他寫入請求。若要更新原子計數器，`UpdateExpression` 參數請使用屬性類型為 `Number` 的 `updateItem`，`Action` 使用 `ADD`。

下列範例示範這項作業，將 `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 軟體開發套件 API 來刪除項目的步驟。

1. 建立 `AmazonDynamoDBClient` 類別的執行個體。

1. 您可以透過建立 `DeleteItemRequest` 類別的執行個體來提供必要的參數。

    若要刪除項目，需要有資料表名稱及項目的主索引鍵。

1. 提供您在前一個步驟中建立的 `DeleteItem` 物件來執行 `DeleteItemRequest` 方法。

**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` 指定只有不再發行的書籍項目才可刪除 (InPublication 屬性值為 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 開發套件 API 來擷取多個項目的步驟。

1. 建立 `AmazonDynamoDBClient` 類別的執行個體。

1. 透過建立 `BatchWriteItemRequest` 類別的執行個體來說明所有的放入與刪除操作。

1. 提供您在前一個步驟中建立的 `BatchWriteItem` 物件來執行 `BatchWriteItemRequest` 方法。

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. 提供您在前一個步驟中建立的 `BatchGetItem` 物件來執行 `BatchGetItemRequest` 方法。

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>

下列 C\$1 程式碼範例使用 `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();
            }
        }
    }
}
```