

# DynamoDB での更新式の使用
<a name="Expressions.UpdateExpressions"></a>

`UpdateItem` オペレーションは、既存項目を更新します。また、存在しない場合は新しい項目をテーブルに追加します。更新する項目のキーを指定する必要があります。また、変更する属性を示す更新式と、その式に割り当てる値も指定する必要があります。

*更新式*は、`UpdateItem` が項目の属性を変更する方法を指定します。たとえば、スカラー値を設定したり、リストまたはマップから要素を削除したりします。

更新式の構文の概要を次に示します。

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

更新式は、1 つ以上の句で構成されます。各句は、`SET`、`REMOVE`、`ADD`、または `DELETE` キーワードで始まります。これらのいずれの句も、任意の順序で更新式に含めることができます。ただし、各アクションキーワードは 1 回のみ表示できます。

各句内には、カンマで区切った 1 つ以上のアクションがあります。各アクションはデータ変更を表します。

このセクションの例は、`ProductCatalog` の [DynamoDB でのプロジェクション式の使用](Expressions.ProjectionExpressions.md) 項目に基づいています。

以下のトピックでは、`SET` アクションのさまざまなユースケースについて説明します。

**Topics**
+ [SET — 項目属性の変更または追加](#Expressions.UpdateExpressions.SET)
+ [REMOVE — 項目から属性を削除](#Expressions.UpdateExpressions.REMOVE)
+ [ADD — 数値とセットの更新](#Expressions.UpdateExpressions.ADD)
+ [DELETE — セットから要素を削除](#Expressions.UpdateExpressions.DELETE)
+ [複数の更新式を使用する](#Expressions.UpdateExpressions.Multiple)

## SET — 項目属性の変更または追加
<a name="Expressions.UpdateExpressions.SET"></a>

1 つ以上の属性を項目に追加するには、更新式で `SET` アクションを使用します。これらのいずれかの属性が既に存在する場合、新しい値で上書きされます。既存の属性の上書きを回避するには、`SET` で `if_not_exists` 関数を使用できます。`if_not_exists` 関数は `SET` アクションに固有で、更新式でのみ使用できます。

`SET` を使用してリスト要素を更新すると、その要素のコンテンツは、指定した新しいデータで置き換えられます。要素が既に存在していない場合、`SET` はリストの末尾に新しい要素を追加します。

1 つの `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] は 2 番目の要素、という順番で表されることに注意してください。  

```
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` はリストの末尾に新しい要素を追加します。  
1 つの `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)`

この関数は、入力として 2 つのリストを受け取り、`list2` のすべての要素を ` list1` に追加します。

**Example**  
[リストに要素を追加](#Expressions.UpdateExpressions.SET.AddingListElements) で、`RelatedItems` リストを追加し `Hammer` と `Nails` の 2 つの要素を追加します。次に、`RelatedItems` の末尾にさらに 2 つの要素を追加します。  

```
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` の*先頭*にもう 1 つの要素を追加します。これを実行するには、`list_append` 要素の順序を入れ替えます。(`list_append` は 2 つのリストを入力し、1 番目のリストに 2 番目のリストを追加することに注意してください)。  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET #ri = list_append(:vals, #ri)" \
    --expression-attribute-names '{"#ri": "RelatedItems"}' \
    --expression-attribute-values '{":vals": {"L": [ { "S": "Chisel" }]}}' \
    --return-values ALL_NEW
```
生成される `RelatedItems` 属性には次の順序で 5 つの要素が含まれます。`Chisel`、`Hammer`、`Nails`、`Screwdriver`、 `Hacksaw`。

### 既存の属性の上書きを防止
<a name="Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites"></a>

**Example**  
項目にすでに `Price` 属性がない場合にのみ、項目の `Price` を設定します (`Price` がすでに存在する場合は何も起こりません)。  

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

## REMOVE — 項目から属性を削除
<a name="Expressions.UpdateExpressions.REMOVE"></a>

1 つ以上の属性を Amazon DynamoDB の項目から削除するには、更新式で `REMOVE` アクションを使用します。複数の `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) で、5 つの要素を含むようにリスト属性 (`RelatedItems`) を変更します。  
+ `[0]`—`Chisel`
+ `[1]`—`Hammer`
+ `[2]`—`Nails`
+ `[3]`—`Screwdriver`
+ `[4]`—`Hacksaw`
次の AWS Command Line Interface (AWS CLI) の例では、リストから `Hammer` と `Nails` を削除します。  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "REMOVE RelatedItems[1], RelatedItems[2]" \
    --return-values ALL_NEW
```
`Hammer` と `Nails` を削除すると、残りの要素は変わります。リストには以下が含まれます。  
+ `[0]`—`Chisel`
+ `[1]`—`Screwdriver`
+ `[2]`—`Hacksaw`

## ADD — 数値とセットの更新
<a name="Expressions.UpdateExpressions.ADD"></a>

**注記**  
一般的に、べき等なオペレーションを確保するために `ADD` ではなく `SET` を使用することをお勧めします。

項目に新しい属性および値を追加するには、更新式で `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` を 2 つの要素を持つ文字列セットに設定します。

```
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` データ型のみをサポートします。

1 つ以上の要素をセットから削除するには、更新式で `DELETE` アクションを使用します。複数の `DELETE` アクションを実行するには、オペレーションをカンマで区切ります。

次の構文の概要について説明します。
+ *path* 要素は、属性へのドキュメントパスです。属性はセットデータ型である必要があります。
+ *サブセット*は *path* から削除する 1 つ以上の要素です。*サブセット*はセット型として指定する必要があります。

```
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 アクションを 1 つのステートメントで使用できます。このオペレーションでは、`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**  
リストに追加しつつ別の属性の値も変更したい場合は、1 つのステートメントで 2 つの SET アクションを使用できます。このオペレーションでは、`RelatedItems` リスト属性に「Nails」が追加され、`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
```