

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

# 在 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)

## 讀取項目
<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`：不傳回寫入容量的詳細資訊。(此為預設值)。

  

**注意**  
與全域次要索引不同，本機次要索引會與其資料表共用佈建的輸送容量。本機次要索引上的讀取和寫入活動會使用其資料表佈建的輸送容量。