

# DynamoDB의 항목 및 속성 작업
<a name="WorkingWithItems"></a>

Amazon DynamoDB에서 *항목*은 속성 모음입니다. 각 속성마다 이름과 값이 있습니다. 속성 값은 스칼라, 세트 또는 문서 유형일 수 있습니다. 자세한 내용은 [Amazon DynamoDB: 작동 방식](HowItWorks.md) 섹션을 참조하세요.

DynamoDB는 기본 CRUD(생성/읽기/업데이트/삭제) 기능을 위한 다음 네 가지 작업을 제공합니다. 이 모든 작업은 원자성입니다.
+ `PutItem` - 항목을 생성합니다.
+ `GetItem` - 항목을 읽습니다.
+ `UpdateItem` - 항목을 업데이트합니다.
+ `DeleteItem` - 항목을 삭제합니다.

이러한 각 작업에서는 작업할 항목의 기본 키를 지정해야 합니다. 예를 들어, `GetItem`을 사용하여 항목을 읽으려면 해당 항목에 대한 파티션 키와 정렬 키(적용 가능한 경우)를 지정해야 합니다.

네 개의 기본 CRUD 작업에 추가하여 DynamoDB는 다음과 같은 작업도 제공합니다.
+ `BatchGetItem` - 하나 이상의 테이블에서 최대 100개의 항목을 읽습니다.
+ `BatchWriteItem` - 하나 이상의 테이블에서 최대 25개의 항목을 생성하거나 삭제합니다.

이러한 배치 작업은 여러 CRUD 작업을 단일 요청으로 결합니다. 또한 배치 작업은 항목 읽기 및 쓰기를 병렬로 실행하여 응답 지연 시간을 최소화합니다.

이 섹션에서는 이 작업을 사용하는 방법을 설명하며 조건부 업데이트 및 원자성 카운터와 같은 관련 주제도 다룹니다. 이 섹션에는 AWS SDK를 사용하는 예제 코드도 포함되어 있습니다.

**Topics**
+ [DynamoDB 항목 크기 및 형식](CapacityUnitCalculations.md)
+ [항목 읽기](#WorkingWithItems.ReadingData)
+ [항목 쓰기](#WorkingWithItems.WritingData)
+ [반환 값](#WorkingWithItems.ReturnValues)
+ [배치 작업](#WorkingWithItems.BatchOperations)
+ [원자성 카운터](#WorkingWithItems.AtomicCounters)
+ [조건부 쓰기](#WorkingWithItems.ConditionalUpdate)
+ [DynamoDB에서 표현식 사용](Expressions.md)
+ [DynamoDB에서 TTL(Time To Live) 사용](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 이진수 인코딩을 사용하는 유니코드입니다. **문자열의 크기는 (속성 이름의 UTF-8로 인코딩된 바이트 수) \$1 (UTF-8로 인코딩된 바이트 수)입니다.
+ 숫자는 유효 숫자 자릿수 38자까지 길이가 다양합니다. 앞과 끝의 0은 잘립니다. 숫자의 크기는 대략 **(속성 이름의 UTF-8로 인코딩된 바이트 수) \$1 (유효 숫자 2자리당 1바이트) \$1 (1바이트)입니다.
+ 이진 값을 DynamoDB로 보내려면 base64 형식으로 인코딩해야 하지만, 크기 계산에는 이 값의 원래 바이트 길이를 사용합니다. 바이너리 속성의 크기는 **(속성 이름의 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`의 기본값은 DynamoDB에서 수정된 속성에 대한 정보를 반환하지 않는 `NONE`입니다.

다음은 DynamoDB API 작업에서 구성되는 `ReturnValues`에 대한 기타 유효한 설정입니다.

### 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` 요청에 5개 항목이 포함되어 있으면 DynamoDB는 사용자를 대신하여 5개의 `GetItem` 작업을 수행합니다. 마찬가지로, `BatchWriteItem` 요청에 추가 요청 두 개와 삭제 요청 네 개가 포함되어 있으면 DynamoDB는 `PutItem` 요청 두 개와 `DeleteItem` 요청 네 개를 수행합니다.

일반적으로 배치에 있는 *모든* 요청이 실패하지 않는 한 배치 작업은 실패하지 않습니다. 예를 들어 `BatchGetItem` 작업을 수행하지만 배치에 있는 개별 `GetItem` 요청 중 하나가 실패한다고 가정합니다. 이 경우 `BatchGetItem`은 실패한 `GetItem` 요청에서 키와 데이터를 반환합니다. 배치에 있는 기타 `GetItem` 요청은 영향을 받지 않습니다.

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

단일 `BatchGetItem` 작업은 최대 100개의 개별 `GetItem` 요청을 포함할 수 있으며, 최대 16MB의 데이터를 검색할 수 있습니다. 또한 `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` 요청을 포함할 수 있으며, 최대 16MB의 데이터를 쓸 수 있습니다. (개별 항목의 최대 크기는 400KB입니다.) 또한 `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` 작업을 사용하여 *원자성 카운터*를 구현할 수 있습니다. 이는 다른 쓰기 요청과 충돌하지 않고 조건 없이 증감되는 숫자 속성입니다. 모든 쓰기 요청은 수신된 순서대로 적용됩니다. 원자성 카운터가 있으면 업데이트는 idempotent 방식이 아닙니다. 다시 말해서, `UpdateItem`을 호출할 때마다 숫자 값이 증가하거나 감소합니다. 원자성 카운터를 업데이트하는 데 사용되는 증분 값이 양수이면 수가 많게 계산될 수 있습니다. 증분 값이 음수이면 수가 적게 계산될 수 있습니다.

원자성 카운터를 사용하여 웹 사이트의 방문객 수를 계속 추적할 수 있습니다. 이 경우 애플리케이션은 현재 값과 상관없이 숫자 값을 계속 증가시킵니다. `UpdateItem` 작업이 실패할 경우 애플리케이션은 작업을 단순히 재시도할 수 있습니다. 이렇게 하면 카운터를 두 번 업데이트할 위험이 있지만, 웹 사이트 방문객 수를 약간 많게 또는 적게 계산하는 것을 허용할 수 있습니다.

수를 많게 또는 적게 계산하는 것을 허용할 수 없는 경우에는(예: 은행 애플리케이션) 원자성 카운터가 적합하지 않습니다. 이러한 경우 원자성 카운터 대신 조건부 업데이트를 사용하는 것이 더 안전합니다.

자세한 내용은 [수치 속성 증가 및 감소](Expressions.UpdateExpressions.md#Expressions.UpdateExpressions.SET.IncrementAndDecrement) 섹션을 참조하세요.

**Example**  
다음은 제품의 AWS CLI가 5씩 증가하는 `Price` 예입니다. 이 예에서는 카운터가 업데이트되기 전에 항목이 존재하는 것으로 알려져 있습니다. `UpdateItem`은 멱등성이 없으므로 이 코드를 실행할 때마다 `Price`가 증가합니다.  

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

## 조건부 쓰기
<a name="WorkingWithItems.ConditionalUpdate"></a>

기본적으로 DynamoDB 쓰기 작업(`PutItem`, `DeleteItem`)은 *무조건적*입니다. 즉, 이러한 각 작업은 지정된 프라이머리 키가 있는 기존 항목을 덮어씁니다.

DynamoDB는 선택적으로 이러한 작업의 조건부 쓰기를 지원합니다. 조건부 쓰기는 항목 속성이 하나 이상의 예상 조건과 일치하는 경우에만 성공합니다. 그렇지 않으면 오류를 반환합니다.

조건부 쓰기는 가장 최근에 업데이트된 항목 버전과 비교하여 조건을 확인합니다. 항목이 이전에 존재하지 않았거나 해당 항목에 대해 가장 최근에 성공한 작업이 삭제인 경우 조건부 쓰기는 이전 항목을 찾지 못한다는 점에 유의하시기 바랍니다.

 조건부 쓰기는 많은 상황에서 유용합니다. 예를 들면 동일한 기본 키가 있는 항목이 아직 없는 경우에만 `PutItem` 작업이 성공하도록 하려고 합니다. 또는 속성 중 하나에 특정 값이 있으면 `UpdateItem` 작업을 통해 항목을 수정할 수 없도록 할 수 있습니다.

조건부 쓰기는 여러 사용자가 동일한 항목을 수정하려고 시도하는 경우에 유용합니다. 두 명의 사용자(Alice와 Bob)가 DynamoDB 테이블에서 동일한 항목을 작업하고 있는 다음 다이어그램을 생각해 봅니다.

![\[사용자 Alice와 Bob은 Id 1을 사용하여 항목을 수정하려고 시도하는데, 이는 조건부 쓰기가 필요함을 보여줍니다.\]](http://docs.aws.amazon.com/ko_kr/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/ko_kr/amazondynamodb/latest/developerguide/images/update-yes-condition.png)


처음에 Alice는 현재 `Price`가 10인 경우에만 `Price`를 8로 업데이트하려고 시도합니다.

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

`--expression-attribute-values`의 인수는 `expression-attribute-values.json` 파일에 저장됩니다.

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

조건이 true로 평가되기 때문에 Alice의 업데이트가 성공합니다.

다음에 Bob은 현재 `Price`가 10인 경우에만 `Price`를 12로 업데이트하려고 시도합니다. 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>

업데이트 할 동일한 속성에 대한 조건부 검사의 경우 조건부 쓰기는 *idempotent*가 될 수 있습니다. 즉, 항목의 특정 속성 값이 요청 시 원하는 값과 일치하는 경우에만 DynamoDB가 해당 쓰기 요청을 수행합니다.

예를 들어, `UpdateItem`가 현재 20인 경우에만 항목의 `Price`를 3으로 증가시키는 `Price` 요청을 실행한다고 가정합니다. 요청을 보낸 후 결과를 다시 받기 전에 네트워크 오류가 나타나고 요청이 성공적이었는지 여부를 알 수 없습니다. 이 조건부 쓰기는 멱등성 방식이기 때문에 동일한 `UpdateItem` 요청을 재시도할 수 있으며 `Price`가 현재 20인 경우에만 DynamoDB가 항목을 업데이트합니다.

### 조건부 쓰기에서 사용된 용량 단위
<a name="WorkingWithItems.ConditionalWrites.ReturnConsumedCapacity"></a>

조건부 쓰기 중에 `ConditionExpression`이 false로 평가되는 경우에도 DynamoDB는 테이블에서 쓰기 용량을 사용합니다. 사용되는 양은 기존 항목의 크기(또는 최소 1개)에 따라 달라집니다. 예를 들어 기존 항목이 300kb이고 새로 만들거나 업데이트하려는 항목이 310kb인 경우, 사용되는 쓰기 용량 단위는 조건이 충족되지 않으면 300, 조건이 충족되면 310이 됩니다. 새 항목(기존 항목 없음)인 경우, 사용되는 쓰기 용량 단위는 조건이 충족되지 않으면 1, 조건이 충족되면 310이 됩니다.

**참고**  
쓰기 작업은 *쓰기* 용량 단위만 사용합니다. 이 작업은 *읽기* 용량 단위를 사용하지 않습니다.

조건부 쓰기가 실패하면 `ConditionalCheckFailedException`이 반환됩니다. 이 상황이 발생하면 사용된 쓰기 용량에 대한 정보를 응답에서 받을 수 없습니다.

조건부 쓰기 중에 사용된 쓰기 용량 단위 수를 반환하려면 `ReturnConsumedCapacity` 파라미터를 사용합니다.
+ `TOTAL` - 사용된 총 쓰기 용량 단위 수를 반환합니다.
+ `INDEXES` - 사용된 총 쓰기 용량 단위 수와 작업의 영향을 받은 테이블 및 보조 인덱스의 소계를 반환합니다.
+ `NONE` - 쓰기 용량 세부 정보를 반환하지 않습니다. (이 값이 기본값입니다.)

  

**참고**  
글로벌 보조 인덱스와 달리 로컬 보조 인덱스는 프로비저닝된 처리 용량을 해당 테이블과 공유합니다. 로컬 보조 인덱스에서의 읽기 또는 쓰기 작업에는 테이블의 프로비저닝된 처리 용량이 사용됩니다.

# DynamoDB에서 표현식 사용
<a name="Expressions"></a>

Amazon DynamoDB에서는 *표현식*을 사용하여 항목에서 읽을 속성을 지정하고, 조건이 충족될 때 데이터를 쓰고, 항목을 업데이트하는 방법을 지정하고, 쿼리를 정의하고, 쿼리 결과를 필터링할 수 있습니다.

이 표에서는 기본 표현식 문법과 사용 가능한 표현식 종류를 설명합니다.


| 표현식 유형 | 설명 | 
| --- | --- | 
| 프로젝션 표현식 | 프로젝션 표현식은 GetItem, Query 또는 Scan과 같은 작업을 사용할 때 항목에서 검색하려는 속성을 식별합니다. | 
| 조건 표현식 | 조건 표현식은 PutItem, UpdateItem 및 DeleteItem 작업을 사용할 때 수정해야 하는 항목을 결정합니다. | 
| 업데이트 표현식 | 업데이트 표현식은 UpdateItem이 항목의 속성을 수정하는 방법을 지정합니다(예: 스칼라 값 설정 또는 목록이나 맵에서 요소 제거). | 
| 키 조건 표현식 | 키 조건 표현식은 쿼리가 테이블 또는 인덱스에서 읽을 항목을 결정합니다. | 
| 필터 표현식 | 필터 표현식은 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` 맵. 각 요소가 평점과 해당 평점에 상응하는 리뷰 목록을 나타냅니다. 처음에 이 맵은 별 5개 및 1개 리뷰로 채워집니다.

## 최상위 속성
<a name="Expressions.Attributes.TopLevelAttributes"></a>

속성이 다른 속성 내부에 포함되어 있지 않은 경우 이러한 속성을 *최상위*라고 합니다. `ProductCatalog` 항목의 경우 최상위 속성은 다음과 같습니다.
+ `Id`
+ `Title`
+ `Description`
+ `BicycleType`
+ `Brand`
+ `Price`
+ `Color`
+ `ProductCategory`
+ `InStock`
+ `QuantityOnHand`
+ `RelatedItems`
+ `Pictures`
+ `ProductReviews`
+ `Comment`
+ `Safety.Warning`

이러한 최상위 속성은 `Color`(목록), `RelatedItems`(목록), `Pictures`(맵) 및 `ProductReviews`(맵)를 제외하고 모두 스칼라입니다.

## 중첩 속성
<a name="Expressions.Attributes.NestedAttributes"></a>

속성이 다른 속성 내부에 포함되어 있는 경우 이러한 속성을 *중첩*이라고 합니다. 중첩 속성에 액세스하려면 *역참조 연산자*를 사용합니다.
+ `[n]` - 목록 요소의 경우
+ `.`(점) - 맵 요소의 경우

### 목록 요소에 액세스
<a name="Expressions.Attributes.NestedElements.AccessingListElements"></a>

목록 요소의 역참조 연산자는 **[*N*]**이며, 여기에서 *n*은 요소 번호입니다. 목록 요소는 0부터 시작되므로 [0]은 목록의 첫 번째 요소, [1]은 두 번째 요소를 나타냅니다. 여기 몇 가지 예가 있습니다:
+ `MyList[0]`
+ `AnotherList[12]`
+ `ThisList[5][11]`

`ThisList[5]` 요소 자체는 하나의 중첩된 목록입니다. 그러므로 `ThisList[5][11]`은 해당 목록의 열두 번째 요소를 나타냅니다.

대괄호 내부의 숫자는 음수가 아닌 정수여야 합니다. 그러므로 다음 표현식은 유효하지 않습니다.
+ `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` 목록의 세 번째 요소입니다. 목록 요소는 0부터 시작합니다.

  `RelatedItems[2]`
+ 제품의 전면도 그림입니다.

  `Pictures.FrontView`
+ 모든 별 5개 리뷰입니다.

  `ProductReviews.FiveStar`
+ 별 5개 리뷰 중 첫 번째 리뷰입니다.

  `ProductReviews.FiveStar[0]`

**참고**  
문서 경로의 최대 깊이는 32입니다. 따라서 경로의 역참조 연산자 수는 이 제한을 초과할 수 없습니다.

다음 요구 사항을 충족하는 한 문서 경로에 모든 속성 이름을 사용할 수 있습니다.
+ 첫 번째 문자는 `a-z`, `A-Z` 또는 `0-9`여야 합니다.
+ 두 번째 문자(있는 경우)는 `a-z` 또는 `A-Z`여야 합니다.

**참고**  
속성 이름이 이 요구 사항을 충족하지 않으면 표현식 속성 이름을 자리 표시자로 정의해야 합니다.

자세한 내용은 [DynamoDB의 표현식 속성 이름(별칭)](Expressions.ExpressionAttributeNames.md) 섹션을 참조하세요.

# DynamoDB의 표현식 속성 이름(별칭)
<a name="Expressions.ExpressionAttributeNames"></a>

*표현식 속성 이름*은 Amazon DynamoDB 표현식에서 실제 속성 이름의 대체 이름으로 사용하는 별칭(자리 표시자)입니다. 표현식 속성 이름은 파운드 기호(`#`)로 시작해야 하며, 그 뒤에 하나 이상의 영숫자가 이어져야 합니다. 밑줄(`_`) 문자도 사용할 수 있습니다.

이 섹션에서는 표현식 속성 이름을 사용해야 하는 여러 가지 상황에 대해 설명합니다.

**참고**  
이 섹션의 예제에서는 AWS Command Line Interface(AWS CLI)를 사용합니다.

**Topics**
+ [예약어](#Expressions.ExpressionAttributeNames.ReservedWords)
+ [특수 문자가 포함된 속성 이름](#Expressions.ExpressionAttributeNames.AttributeNamesContainingSpecialCharacters)
+ [중첩 속성](#Expressions.ExpressionAttributeNames.NestedAttributes)
+ [속성 이름 반복 참조](#Expressions.ExpressionAttributeNames.RepeatingAttributeNames)

## 예약어
<a name="Expressions.ExpressionAttributeNames.ReservedWords"></a>

경우에 따라 DynamoDB 예약어와 충돌하는 속성 이름을 포함하는 표현식을 작성해야 할 때가 있습니다. 전체 예약어 목록은 [DynamoDB의 예약어](ReservedWords.md)를 참조하세요.

예를 들어, 다음 AWS CLI 예제는 `COMMENT`가 예약어이기 때문에 실패합니다.

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

이 문제를 해결하려면 `Comment`를 `#c`와 같은 표현식 속성 이름으로 대체할 수 있습니다. `#`(파운드 기호)가 필요하며 이 기호는 속성 이름의 자리 표시자임을 나타냅니다. 이제 AWS CLI 예제는 다음과 같습니다.

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

**참고**  
속성 이름이 숫자로 시작하거나 공백을 포함하거나 예약어를 포함하는 경우, *반드시* 표현식 속성 이름을 사용하여 표현식에서 해당 속성의 이름을 대체해야 합니다.

## 특수 문자가 포함된 속성 이름
<a name="Expressions.ExpressionAttributeNames.AttributeNamesContainingSpecialCharacters"></a>

식에서 점(".")은 문서 경로의 특수 문자로 해석됩니다. 하지만 DynamoDB에서는 점 문자 및 하이픈('-')과 같은 기타 특수 문자를 속성 이름의 일부로 사용할 수도 있습니다. 이러한 사용은 경우에 따라 의미가 명확하지 않을 수도 있습니다. 설명을 위해 `Safety.Warning` 항목에서 `ProductCatalog` 속성을 가져오려 한다고 가정합니다([DynamoDB에서 표현식 사용 시 항목 속성 참조](Expressions.Attributes.md) 참조).

프로젝션 표현식을 사용하여 `Safety.Warning`에 액세스하려 한다고 가정하겠습니다.

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

DynamoDB는 예상 문자열("`Always wear a helmet`")이 아닌 빈 결과를 반환합니다. 이는 DynamoDB가 표현식의 점을 문서 경로 구분 기호로 해석하기 때문입니다. 이 경우 표현식 속성 이름(`#sw`)을 `Safety.Warning`의 대체 이름으로 정의해야 합니다. 그러고 나면 다음 프로젝션 표현식을 사용할 수 있습니다.

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

그러면 DynamoDB에서 정확한 결과가 반환됩니다.

**참고**  
속성 이름에 점('.') 또는 하이픈('-') 이 포함된 경우 *반드시* 표현식 속성 이름을 사용하여 표현식에서 해당 속성의 이름을 대체해야 합니다.

## 중첩 속성
<a name="Expressions.ExpressionAttributeNames.NestedAttributes"></a>

중첩된 속성 `ProductReviews.OneStar`에 액세스하려고 한다고 가정해 보겠습니다. 표현식 속성 이름에서 DynamoDB는 점(".")을 속성 이름 내의 문자로 취급합니다. 중첩된 속성을 참조하려면 문서 경로에 있는 각 요소의 표현식 속성 이름을 정의합니다.
+ `#pr — ProductReviews`
+ `#1star — OneStar`

이제 프로젝션 표현식에 `#pr.#1star`를 사용할 수 있습니다.

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

그러면 DynamoDB에서 정확한 결과가 반환됩니다.

## 속성 이름 반복 참조
<a name="Expressions.ExpressionAttributeNames.RepeatingAttributeNames"></a>

표현식 속성 이름은 동일한 속성 이름을 반복적으로 참조해야 할 때 도움이 됩니다. 예를 들어 `ProductCatalog` 항목에서 리뷰 몇 개를 검색하는 다음 식을 살펴보겠습니다.

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

식을 간소화하기 위해 `ProductReviews`를 `#pr`과 같은 식 속성 이름으로 대체할 수 있습니다. 수정된 표현식은 다음과 같습니다.
+  `#pr.FiveStar, #pr.ThreeStar, #pr.OneStar` 

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

식 속성 이름을 정의하는 경우 전체 식에서 해당 식 속성 이름을 일관되게 사용해야 합니다. 또한 `#` 기호를 생략하면 안 됩니다.

# DynamoDB에서 표현식 속성 값 사용
<a name="Expressions.ExpressionAttributeValues"></a>

Amazon DynamoDB의 *표현식 속성 값*은 변수로 작동합니다. 이 값은 런타임까지 모를 수 있는 비교하려는 실제 값을 대체합니다. 표현식 속성 값은 콜론(`:`)으로 시작해야 하고, 그 뒤에 하나 이상의 영숫자가 와야 합니다.

예를 들어 `ProductCatalog`에서 사용 가능하고 비용이 `Black` 이하인 모든 `500` 항목을 반환하고 싶었다고 가정합니다. 다음 이 `Scan`(AWS Command Line Interface) 예제와 같이 필터 표현식과 함께 AWS CLI 작업을 사용할 수 있습니다.

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

`--expression-attribute-values`의 인수는 `values.json` 파일에 저장됩니다.

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

식 속성 값을 정의하는 경우 전체 식에서 해당 식 속성 이름을 일관되게 사용해야 합니다. 또한 `:` 기호를 생략하면 안 됩니다.

표현식 속성 값은 키 조건 표현식, 조건 표현식, 업데이트 표현식 및 필터 표현식에서 사용됩니다.

# DynamoDB에서 프로젝션 표현식 사용
<a name="Expressions.ProjectionExpressions"></a>

테이블에서 데이터를 읽으려면 `GetItem`, `Query`, `Scan` 등과 같은 작업을 사용합니다. Amazon DynamoDB는 기본적으로 모든 항목 속성을 반환합니다. 모든 속성 대신 일부 속성만 가져오려면 프로젝션 표현식을 사용합니다.

*프로젝션 표현식*은 원하는 속성을 식별하는 문자열입니다. 단일 속성을 가져오려면 속성의 이름을 지정합니다. 여러 속성의 경우 이름을 쉼표로 구분해야 합니다.

`ProductCatalog`의 [DynamoDB에서 표현식 사용 시 항목 속성 참조](Expressions.Attributes.md) 항목을 기반으로 한 프로젝션 표현식의 몇 가지 예는 다음과 같습니다.
+ 단일 최상위 속성입니다.

  `Title `
+ 세 가지 최상위 속성입니다. DynamoDB는 전체 `Color` 집합을 검색합니다.

  `Title, Price, Color`
+ 네 가지 최상위 속성입니다. 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* 요소는 항목의 문서 경로입니다.
+ **피연산자** 요소는 항목의 문서 경로 또는 함수일 수 있습니다.

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

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

operand ::=
    path | function

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

항목의 지정된 경로에 속성이 포함되지 않으면 `if_not_exists`가 `value`로 평가됩니다. 그렇지 않으면 `path`로 평가됩니다.

다음 `PutItem` 작업은 예제에서 참조할 샘플 항목을 생성합니다.

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

`--item`의 인수는 `item.json` 파일에 저장됩니다. 간소화를 위해 항목 속성 몇 개만 사용됩니다.

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

**Topics**
+ [속성 수정](#Expressions.UpdateExpressions.SET.ModifyingAttributes)
+ [목록 및 맵 추가](#Expressions.UpdateExpressions.SET.AddingListsAndMaps)
+ [목록에 요소 추가](#Expressions.UpdateExpressions.SET.AddingListElements)
+ [중첩 맵 속성 추가](#Expressions.UpdateExpressions.SET.AddingNestedMapAttributes)
+ [수치 속성 증가 및 감소](#Expressions.UpdateExpressions.SET.IncrementAndDecrement)
+ [목록에 요소 추가](#Expressions.UpdateExpressions.SET.UpdatingListElements)
+ [기존 속성의 덮어쓰기 방지](#Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites)

### 속성 수정
<a name="Expressions.UpdateExpressions.SET.ModifyingAttributes"></a>

**Example**  
`ProductCategory` 및 `Price` 속성을 업데이트합니다.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET ProductCategory = :c, Price = :p" \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
`--expression-attribute-values`의 인수는 `values.json` 파일에 저장됩니다.  

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

**참고**  
`UpdateItem` 작업에서 `--return-values ALL_NEW`를 실행하면 DynamoDB에서 업데이트 후 나타나는 항목을 반환합니다.

### 목록 및 맵 추가
<a name="Expressions.UpdateExpressions.SET.AddingListsAndMaps"></a>

**Example**  
새 목록과 새 맵을 추가합니다.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET RelatedItems = :ri, ProductReviews = :pr" \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
`--expression-attribute-values`의 인수는 `values.json` 파일에 저장됩니다.  

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

### 목록에 요소 추가
<a name="Expressions.UpdateExpressions.SET.AddingListElements"></a>

**Example**  
새로운 속성을 `RelatedItems` 목록에 추가합니다. 목록 요소는 0부터 시작되므로 [0]은 목록의 첫 번째 요소를 나타내고 [1]은 두 번째 요소를 나타냅니다.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET RelatedItems[1] = :ri" \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
`--expression-attribute-values`의 인수는 `values.json` 파일에 저장됩니다.  

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

**참고**  
`SET`을 사용하여 목록 요소를 업데이트하는 경우 해당 요소의 내용이 사용자가 지정한 새 데이터로 바뀝니다. 요소가 아직 없으면 `SET`은 목록의 끝에 새 요소를 추가합니다.  
단일 `SET` 작업에서 여러 요소를 추가하는 경우 요소가 요소 번호에 따라 순서대로 정렬됩니다.

### 중첩 맵 속성 추가
<a name="Expressions.UpdateExpressions.SET.AddingNestedMapAttributes"></a>

**Example**  
일부 중첩 맵 속성을 추가합니다.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET #pr.#5star[1] = :r5, #pr.#3star = :r3" \
    --expression-attribute-names file://names.json \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
`--expression-attribute-names`의 인수는 `names.json` 파일에 저장됩니다.  

```
{
    "#pr": "ProductReviews",
    "#5star": "FiveStar",
    "#3star": "ThreeStar"
}
```
`--expression-attribute-values`의 인수는 `values.json` 파일에 저장됩니다.  

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

**중요**  
상위 맵이 없는 경우 중첩 맵 속성을 업데이트할 수 없습니다. 상위 맵(`ProductReviews`)이 존재하지 않을 때 중첩 속성(예: `ProductReviews.FiveStar`)을 업데이트하려고 하면 DynamoDB는 *"The document path provided in the update expression is invalid for update"*라는 메시지와 함께 `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` 속성에는 5개의 요소가 `Chisel`, `Hammer`, `Nails`, `Screwdriver`, `Hacksaw` 순서로 포함됩니다.

### 기존 속성의 덮어쓰기 방지
<a name="Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites"></a>

**Example**  
항목에 `Price` 속성이 아직 없는 경우에만 항목의 `Price`를 설정합니다. (`Price`가 이미 있는 경우 아무 동작도 발생하지 않습니다.)  

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

## REMOVE - 항목에서 속성 삭제
<a name="Expressions.UpdateExpressions.REMOVE"></a>

업데이트 표현식에서 `REMOVE` 작업을 사용하여 Amazon DynamoDB에서 하나 이상의 속성을 항목에서 제거합니다. 여러 `REMOVE` 작업을 수행하려면 각 작업을 쉼표로 구분합니다.

다음은 업데이트 식의 `REMOVE`에 대한 구문을 요약한 것입니다. 제거하려는 속성의 문서 경로가 유일한 피연산자입니다.

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

**Example**  
항목에서 일부 속성을 제거합니다. (이 속성이 없는 경우 아무 동작도 발생하지 않습니다.)  

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

### 목록에서 요소 제거
<a name="Expressions.UpdateExpressions.REMOVE.RemovingListElements"></a>

`REMOVE`를 사용하여 목록에서 개별 요소를 삭제합니다.

**Example**  
[목록에 요소 추가](#Expressions.UpdateExpressions.SET.UpdatingListElements)에서 다음 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` 또는 집합 데이터 형식이어야 합니다.
+ *값* 요소는 속성에 더할 숫자(`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* 요소는 속성에 대한 문서 경로입니다. 속성은 설정된 Set 데이터 형식이어야 합니다.
+ *하위 집합*은 *경로*에서 삭제하려는 하나 이상의 요소입니다. *하위 집합*을 집합 형식으로 지정해야 합니다.

```
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` 목록 속성에 '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
```

# DynamoDB의 조건 및 필터 표현식, 연산자, 함수
<a name="Expressions.OperatorsAndFunctions"></a>

DynamoDB 테이블에서 데이터를 조작하려면 `PutItem`, `UpdateItem` 및 `DeleteItem` 작업을 사용합니다. 이러한 데이터 조작 작업의 경우 조건 표현식을 지정하여 어떤 항목을 수정할지를 결정할 수 있습니다. 조건 표현식이 true로 평가되는 경우 작업이 성공합니다. 그렇지 않으면 작업이 실패합니다.

이 섹션에서는 Amazon DynamoDB에서 필터 표현식 및 조건 표현식을 작성하기 위한 기본 제공 함수와 키워드에 대해 살펴봅니다. [DynamoDB를 사용한 함수 및 프로그래밍에 대한 자세한 내용은 [DynamoDB 및 AWS SDK를 사용한 프로그래밍](Programming.md) 및 DynamoDB API 참조](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/)를 참조하세요.

**Topics**
+ [필터 및 조건 표현식 구문](#Expressions.OperatorsAndFunctions.Syntax)
+ [비교 실행](#Expressions.OperatorsAndFunctions.Comparators)
+ [함수](#Expressions.OperatorsAndFunctions.Functions)
+ [논리 평가](#Expressions.OperatorsAndFunctions.LogicalEvaluations)
+ [괄호](#Expressions.OperatorsAndFunctions.Parentheses)
+ [조건식의 우선 순위](#Expressions.OperatorsAndFunctions.Precedence)

## 필터 및 조건 표현식 구문
<a name="Expressions.OperatorsAndFunctions.Syntax"></a>

아래의 구문 요약에서 *피연산 함수*는 다음과 같이 사용됩니다.
+ `Id`, `Title`, `Description`, `ProductCategory` 등의 최상위 속성
+ 내포 속성을 참조하는 문서 경로

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

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

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

## 비교 실행
<a name="Expressions.OperatorsAndFunctions.Comparators"></a>

다음 비교기를 사용하여 피연산자를 단일 값과 비교합니다.
+ `a = b` - *a*가 *b*와 같은 경우 true입니다.
+ `a <> b` - *a*가 *b*와 같지 않은 경우 true입니다.
+ `a < b` - *a*가 *b*보다 작은 경우 true입니다.
+ `a <= b` - *a*가 *b*보다 작거나 같은 경우 true입니다.
+ `a > b` - *a*가 *b*보다 큰 경우 true입니다.
+ `a >= b` - *a*가 *b*보다 크거나 같은 경우 true입니다.

`BETWEEN` 및 `IN` 키워드를 사용하여 피연산 함수와 값의 범위 또는 열거된 값 목록을 비교합니다.
+ `a BETWEEN b AND c` - *a*가 *b*보다 크거나 같고 *c*보다 작거나 같은 경우 true입니다.
+ `a IN (b, c, d) ` - *a*가 목록의 임의 값(*b*, *c*, *d* 값 등)과 같은 경우 true입니다. 목록에는 쉼표로 구분된 최대 100개의 값이 포함될 수 있습니다.

## 함수
<a name="Expressions.OperatorsAndFunctions.Functions"></a>

다음의 함수를 사용하여 항목에 속성이 존재하는지 판단하거나 속성 값을 평가합니다. 함수 이름은 대/소문자를 구분합니다. 중첩 속성의 경우 전체 문서 경로를 제공해야 합니다.


****  

| 함수 | 설명 | 
| --- | --- | 
|  `attribute_exists (path)`  | `path`에 의해 지정된 속성이 항목에 포함되어 있는 경우 true입니다. 예: `Product` 테이블에 있는 항목에 측면 사진이 있는지를 확인합니다. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/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/ko_kr/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/ko_kr/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) `type` 파라미터에는 반드시 표현식 속성 값을 사용해야 합니다. 예: `QuantityOnHand` 속성이 List 유형인지 확인합니다. 위의 예에서 `:v_sub`가 `L` 문자열의 자리 표시자입니다. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/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/ko_kr/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/ko_kr/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/ko_kr/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) 수식 속성 값인 `:v_sub`가 `Company`의 자리 표시자입니다. 예: 빨간색 제품 색상을 선택할 수 있는지 확인합니다. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/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/ko_kr/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/ko_kr/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  속성이 `Set` 데이터 유형인 경우, `size`에서는 집합에 포함된 요소의 개수가 반환됩니다. 예: 한 가지 이상의 제품 색상을 선택할 수 있는지 확인합니다. 수식 속성 값인 `:v_sub`가 `1`의 자리 표시자입니다. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/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/ko_kr/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  | 

## 논리 평가
<a name="Expressions.OperatorsAndFunctions.LogicalEvaluations"></a>

`AND`, `OR` 및 `NOT` 키워드를 사용하여 논리 평가를 수행합니다. 아래의 목록에서 *a*와 *b*는 평가될 조건을 나타냅니다.
+ `a AND b` - *a*와 *b*가 모두 true인 경우 true입니다.
+ `a OR b` - *a* 또는 *b*(또는 둘 모두)가 true인 경우 true입니다.
+ `NOT a` - *a*가 false인 경우 true입니다. *a*가 true인 경우 false입니다.

다음은 연산에서 AND를 사용한 코드 예제입니다.

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

## 괄호
<a name="Expressions.OperatorsAndFunctions.Parentheses"></a>

논리 평가의 우선 순위를 변경하려면 괄호를 사용합니다. 예를 들어 *a* 및 *b* 조건이 true이고 *c* 조건이 false인 경우를 가정할 수 있습니다. 다음 수식들은 true로 평가됩니다.
+ `a OR b AND c`

그러나 조건을 괄호로 묶으면 해당 조건을 먼저 평가하게 됩니다. 예를 들어 아래의 경우에는 false로 평가됩니다.
+  `(a OR b) AND c`

**참고**  
수식에 괄호를 포함시킬 수 있습니다. 가장 안쪽에 위치한 괄호부터 먼저 평가됩니다.

다음은 논리 평가에 괄호가 포함된 코드 예제입니다.

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

## 조건식의 우선 순위
<a name="Expressions.OperatorsAndFunctions.Precedence"></a>

 DynamoDB는 다음의 우선 순위 규칙을 사용하여 왼쪽에서 오른쪽 방향으로 조건식을 평가합니다.
+ `= <> < <= > >=`
+ `IN`
+ `BETWEEN`
+ `attribute_exists attribute_not_exists begins_with contains`
+ 괄호
+ `NOT`
+ `AND`
+ `OR`

# DynamoDB 조건 표현식 CLI 예제
<a name="Expressions.ConditionExpressions"></a>

다음은 조건 표현식을 사용하는 몇 가지 AWS Command Line Interface(AWS CLI) 예제입니다. 이 예제는 `ProductCatalog`에서 소개된 [DynamoDB에서 표현식 사용 시 항목 속성 참조](Expressions.Attributes.md) 테이블을 기반으로 합니다. 이 테이블의 파티션 키는 `Id`이며 정렬 키는 없습니다. 다음 `PutItem` 작업은 예제에서 참조할 샘플 `ProductCatalog` 항목을 생성합니다.

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

`--item`의 인수는 `item.json` 파일에 저장됩니다. 간소화를 위해 항목 속성 몇 개만 사용됩니다.

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

**Topics**
+ [조건부 추가](#Expressions.ConditionExpressions.PreventingOverwrites)
+ [조건부 삭제](#Expressions.ConditionExpressions.AdvancedComparisons)
+ [조건부 업데이트](#Expressions.ConditionExpressions.SimpleComparisons)
+ [조건부 표현식 예시](#Expressions.ConditionExpressions.ConditionalExamples)

## 조건부 추가
<a name="Expressions.ConditionExpressions.PreventingOverwrites"></a>

`PutItem` 작업은 동일한 프라이머리 키가 있는 항목을 덮어씁니다(있는 경우). 이 동작을 방지하려면 조건 표현식을 사용합니다. 이렇게 하면 해당 항목에 동일한 프라이머리 키가 아직 없는 경우에만 쓰기를 진행할 수 있습니다.

다음 예제에서는 `attribute_not_exists()`를 사용하여, 쓰기 작업을 시도하기 전에 테이블에 프라이머리 키가 있는지 확인합니다.

**참고**  
프라이머리 키가 파티션 키(pk)와 정렬 키(sk)로 구성된 경우 이 파라미터는 쓰기 작업을 시도하기 전에 `attribute_not_exists(pk)` 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는 조건부 요청 실패라는 오류 메시지를 반환합니다.

**참고**  
`attribute_not_exists` 및 기타 함수에 대한 자세한 내용은 [DynamoDB의 조건 및 필터 표현식, 연산자, 함수](Expressions.OperatorsAndFunctions.md)을 참조하세요.

## 조건부 삭제
<a name="Expressions.ConditionExpressions.AdvancedComparisons"></a>

조건부 삭제를 수행하려면 조건 표현식과 함께 `DeleteItem` 작업을 사용합니다. 작업이 성공하려면 조건식이 true로 평가되어야 하며, 그렇지 않으면 작업이 실패합니다.

위에서 정의한 항목을 고려해 보겠습니다.

다음 조건에서만 항목을 삭제하려 한다고 가정합니다.
+  `ProductCategory`는 "스포츠 상품" 또는 "원예용 소모품"입니다.
+  `Price`는 500에서 600 사이입니다.

다음 예제에서는 항목을 삭제하려고 시도합니다.

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

`--expression-attribute-values`의 인수는 `values.json` 파일에 저장됩니다.

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

**참고**  
조건 표현식에서 `:`(콜론 문자)은 실제 값의 자리 표시자인 *표현식 속성 값*을 나타냅니다. 자세한 내용은 [DynamoDB에서 표현식 속성 값 사용](Expressions.ExpressionAttributeValues.md) 섹션을 참조하세요.  
`IN`, `AND` 및 기타 키워드에 대한 자세한 내용은 [DynamoDB의 조건 및 필터 표현식, 연산자, 함수](Expressions.OperatorsAndFunctions.md) 섹션을 참조하세요.

이 예에서 `ProductCategory` 비교는 true로 평가되지만 `Price` 비교는 false로 평가됩니다. 이로 인해 조건 표현식이 false로 평가되고 `DeleteItem` 작업이 실패합니다.

## 조건부 업데이트
<a name="Expressions.ConditionExpressions.SimpleComparisons"></a>

조건부 업데이트를 수행하려면 조건 표현식과 함께 `UpdateItem` 작업을 사용합니다. 작업이 성공하려면 조건식이 true로 평가되어야 하며, 그렇지 않으면 작업이 실패합니다.

**참고**  
`UpdateItem`은 *업데이트 표현식*도 지원하는데, 이 표현식에서 사용자는 항목에 대해 변경하고자 하는 사항을 지정합니다. 자세한 내용은 [DynamoDB에서 업데이트 표현식 사용](Expressions.UpdateExpressions.md) 섹션을 참조하세요.

위에서 정의한 항목으로 시작했다고 가정합니다.

다음 예제에서는 `UpdateItem` 작업을 수행합니다. 이 작업은 제품의 `Price`를 75만큼 감소시키려고 시도하지만, 조건 표현식은 현재 `Price`가 500보다 작거나 같은 경우 업데이트를 방지합니다.

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

`--expression-attribute-values`의 인수는 `values.json` 파일에 저장됩니다.

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

시작 `Price`가 650이면 `UpdateItem` 작업은 `Price`를 575로 감소시킵니다. `UpdateItem` 작업을 다시 실행하면 `Price`는 500으로 감소됩니다. 세 번째로 작업을 실행하면 조건 표현식이 false로 평가되고 업데이트가 실패합니다.

**참고**  
조건 표현식에서 `:`(콜론 문자)은 실제 값의 자리 표시자인 *표현식 속성 값*을 나타냅니다. 자세한 내용은 [DynamoDB에서 표현식 속성 값 사용](Expressions.ExpressionAttributeValues.md) 섹션을 참조하세요.  
"*>*" 및 기타 연산자에 대한 자세한 내용은 [DynamoDB의 조건 및 필터 표현식, 연산자, 함수](Expressions.OperatorsAndFunctions.md)를 참조하세요.

## 조건부 표현식 예시
<a name="Expressions.ConditionExpressions.ConditionalExamples"></a>

다음 예에 사용된 함수에 대한 자세한 내용은 [DynamoDB의 조건 및 필터 표현식, 연산자, 함수](Expressions.OperatorsAndFunctions.md) 섹션을 참조하세요. 표현식에서 다양한 속성 유형을 지정하는 방법에 대한 자세한 내용은 [DynamoDB에서 표현식 사용 시 항목 속성 참조](Expressions.Attributes.md) 섹션을 참조하세요.

### 항목의 속성 확인
<a name="Expressions.ConditionExpressions.CheckingForAttributes"></a>

속성이 존재하는지(또는 존재하지 않는지)를 확인할 수 있습니다. 조건 표현식이 true로 평가되는 경우 작업이 성공하고, 그렇지 않으면 작업이 실패합니다.

다음 예제에서는 `attribute_not_exists`를 사용하여 `Price` 속성이 없는 경우에만 제품을 삭제합니다.

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

DynamoDB는 `attribute_exists` 함수도 제공합니다. 다음 예제에서는 좋지 않은 평가를 받은 경우에만 제품을 삭제합니다.

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

### 속성 유형 확인
<a name="Expressions.ConditionExpressions.CheckingForAttributeType"></a>

`attribute_type` 함수를 사용하여 속성 값의 데이터 형식을 확인할 수 있습니다. 조건 표현식이 true로 평가되는 경우 작업이 성공하고, 그렇지 않으면 작업이 실패합니다.

다음 예제에서는 문자열 집합 형식의 `attribute_type` 속성이 있는 경우에만 `Color`을 사용하여 제품을 삭제합니다.

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

`--expression-attribute-values`의 인수는 expression-attribute-values.json 파일에 저장됩니다.

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

### 문자열 시작 값 확인
<a name="Expressions.ConditionExpressions.CheckingBeginsWith"></a>

`begins_with` 함수를 사용하여 문자열 속성 값이 특정 하위 문자열로 시작하는지 확인할 수 있습니다. 조건 표현식이 true로 평가되는 경우 작업이 성공하고, 그렇지 않으면 작업이 실패합니다.

다음 예제에서는 `begins_with` 맵의 `FrontView` 요소가 특정 값으로 시작하는 경우에만 `Pictures`를 사용하여 제품을 삭제합니다.

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

`--expression-attribute-values`의 인수는 expression-attribute-values.json 파일에 저장됩니다.

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

### 세트의 요소 확인
<a name="Expressions.ConditionExpressions.CheckingForContains"></a>

`contains` 함수를 사용하여 집합의 요소를 확인하거나 문자열 내의 하위 문자열을 찾을 수 있습니다. 조건 표현식이 true로 평가되는 경우 작업이 성공하고, 그렇지 않으면 작업이 실패합니다.

다음 예제에서는 `contains` 문자열 집합에 특정 값을 가진 요소가 있는 경우에만 `Color`를 사용하여 제품을 삭제합니다.

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

`--expression-attribute-values`의 인수는 expression-attribute-values.json 파일에 저장됩니다.

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

### 속성 값의 크기 확인
<a name="Expressions.ConditionExpressions.CheckingForSize"></a>

`size` 함수를 사용하여 속성 값의 크기를 확인할 수 있습니다. 조건 표현식이 true로 평가되는 경우 작업이 성공하고, 그렇지 않으면 작업이 실패합니다.

다음 예제에서는 `size` 이진 속성의 크기가 `VideoClip`바이트보다 큰 경우만 `64000`를 사용하여 제품을 삭제합니다.

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

`--expression-attribute-values`의 인수는 expression-attribute-values.json 파일에 저장됩니다.

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

# DynamoDB에서 TTL(Time To Live) 사용
<a name="TTL"></a>

DynamoDB용 Time To Live(TTL)는 더 이상 관련이 없는 항목을 삭제하기 위한 비용 효율적인 방법입니다. TTL을 사용하면 항목이 더 이상 필요하지 않은 시점을 나타내는 항목별 만료 타임스탬프를 정의할 수 있습니다. DynamoDB는 쓰기 처리량을 소비하지 않고 만료 후 며칠 내에 만료된 항목을 자동으로 삭제합니다.

TTL을 사용하려면 먼저 테이블에서 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에 저장되며, 다른 삭제 작업과 마찬가지로 로컬 보조 인덱스 및 글로벌 보조 인덱스에서 제거됩니다.

글로벌 테이블의 [글로벌 테이블 버전 2019.11.21(현재)](GlobalTables.md)을 사용하고 TTL 기능도 사용한다면 DynamoDB는 TTL 삭제를 모든 복제본 테이블에 복제합니다. 최초 TTL 삭제는 TTL 만료가 발생하는 리전의 쓰기 용량 단위(WCU)를 사용하지 않습니다. 그러나 복제 테이블에 대한 복제 TTL 삭제는 각 복제본 리전에서 프로비저닝된 용량을 사용할 때는 복제된 쓰기 용량 단위를 사용하고, 온디맨드 용량 모드를 사용할 때는 복제된 쓰기 단위를 사용하며 요금이 부과됩니다.

TTL에 대한 자세한 내용은 다음 주제를 참조하십시오.

**Topics**
+ [DynamoDB에서 TTL(Time To Live) 사용](time-to-live-ttl-how-to.md)
+ [DynamoDB에서 TTL(Time To Live) 연산](time-to-live-ttl-before-you-start.md)
+ [만료된 항목 및 TTL(Time To Live) 작업](ttl-expired-items.md)

# DynamoDB에서 TTL(Time To Live) 사용
<a name="time-to-live-ttl-how-to"></a>

**참고**  
TTL 기능이 제대로 작동하는지 디버깅 및 검증하는 데 도움이 되도록 항목 TTL에 제공된 값이 DynamoDB 진단 로그에 일반 텍스트로 로깅됩니다.

Amazon DynamoDB 콘솔, AWS Command Line Interface(AWS CLI)에서 TTL을 활성화하거나 지원되는 AWS SDK와 함께 [Amazon DynamoDB API 참조](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/)를 사용하여 TTL을 활성화할 수 있습니다. 모든 파티션에서 TTL을 활성화하는 데 약 1시간이 걸립니다.

## AWS 콘솔을 사용하여 DynamoDB TTL 활성화
<a name="time-to-live-ttl-how-to-enable-console"></a>

1. AWS Management Console에 로그인하고 [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)에서 DynamoDB 콘솔을 엽니다.

1. **테이블**을 선택한 후 수정하려는 테이블을 선택합니다.

1. **추가 설정** 탭의 **Time To Live(TTL)** 섹션에서 **켜기**를 선택하여 TTL을 활성화합니다.

1. 테이블에서 TTL을 활성화할 경우, DynamoDB에서는 항목이 만료될 수 있는지 여부를 결정할 때 서비스가 검색할 특정 속성 이름을 식별해야 합니다. 아래 표시된 TTL 속성 이름은 대소문자를 구분하며 읽기 및 쓰기 작업에 정의된 속성과 일치해야 합니다. 일치하지 않을 경우 만료된 항목이 삭제되지 않습니다. TTL 속성의 이름을 바꾸려면 TTL을 비활성화했다가 새 속성으로 다시 활성화해야 합니다. TTL은 비활성화된 후에도 약 30분 동안 삭제를 계속 처리합니다. 복원된 테이블에서 TTL을 재구성해야 합니다.  
![\[DynamoDB가 항목의 만료 여부를 결정하는 데 사용하는 대소문자 구분 TTL 속성 이름입니다.\]](http://docs.aws.amazon.com/ko_kr/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')
```

테이블의 TTL 상태를 설명하는 [DescribeTimeToLive](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/client/describe_time_to_live.html) 작업을 사용하여 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를 사용하여 Time To Live 활성화
<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 셸 및 AWS CLI를 사용하여 `TTLExample` 테이블에 유지 시간(TTL) 속성 설정을 갖는 항목을 추가합니다.

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

이 예제에서는 현재 날짜부터 시작하여 여기에 5일을 추가하여 만료 시간을 생성합니다. 그런 다음 만료 시간을 epoch 시간 형식으로 변환하여 `TTLExample` 테이블에 항목을 추가합니다.

**참고**  
 유지 시간(TTL)에 만료 값을 설정하는 한 가지 방법은 초 수를 계산하여 만료 시간을 추가하는 것입니다. 예를 들어, 5일은 432,000초입니다. 하지만 날짜로 시작하여 환산하는 방법이 더 많이 사용됩니다.

다음 예제에서와 같이 현재 시간을 epoch 시간 형식으로 변환하는 방법은 간단합니다.
+ Linux 터미널: `date +%s`
+ Python: `import time; int(time.time())`
+ Java: `System.currentTimeMillis() / 1000L`
+ JavaScript: `Math.floor(Date.now() / 1000)`

## CloudFormation을 사용하여 DynamoDB TTL 활성화
<a name="time-to-live-ttl-how-to-enable-cf"></a>

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

CloudFormation 템플릿 내에서 TTL을 사용하는 방법에 대한 추가 세부 정보는 [여기](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-table-timetolivespecification.html)에서 확인할 수 있습니다.

# DynamoDB에서 TTL(Time To Live) 연산
<a name="time-to-live-ttl-before-you-start"></a>

TTL을 구현하는 일반적인 방법은 항목이 생성되거나 마지막으로 업데이트된 시기를 기준으로 항목의 만료 시간을 설정하는 것입니다. 이를 위해서는 `createdAt` 및 `updatedAt` 타임스탬프에 시간을 추가하면 됩니다. 예를 들어 새로 생성한 항목의 TTL을 `createdAt` \$190일로 설정할 수 있습니다. 항목이 업데이트되면 TTL을 `updatedAt` \$190일로 다시 계산할 수 있습니다.

계산된 만료 시간은 epoch 형식(초)이어야 합니다. 만료 및 삭제 대상으로 간주되려면 TTL이 과거 5년을 초과해서는 안 됩니다. 다른 형식을 사용하는 경우 TTL 프로세스는 해당 항목을 무시합니다. 만료 시간을 항목을 만료하려는 미래 시간으로 설정하면 해당 시점이 지나면 항목이 만료됩니다. 예를 들어 만료 시간을 1724241326(2024년 8월 21일 월요일 11:55:26(UTC))으로 설정했다고 가정해 보겠습니다. 지정된 시간 후 항목이 만료됩니다. 최소 TTL 기간은 없습니다. 만료 시간을 현재 시간으로부터 5분과 같은 미래 시간으로 설정할 수 있습니다. 그러나 DynamoDB는 일반적으로 항목이 만료되는 즉시가 아니라 만료 시간 후 48시간 이내에 만료된 항목을 삭제합니다.

**Topics**
+ [항목 생성 및 Time to Live 설정](#time-to-live-ttl-before-you-start-create)
+ [항목 업데이트 및 Time to Live 새로 고침](#time-to-live-ttl-before-you-start-update)

## 항목 생성 및 Time to Live 설정
<a name="time-to-live-ttl-before-you-start-create"></a>

다음 예시는 TTL 속성 이름으로 `expireAt`을 사용하여 새 항목을 만들 때 만료 시간을 계산하는 방법을 보여줍니다. 대입문은 현재 시간을 변수로 가져옵니다. 이 예시에서는 만료 시간을 현재 시간으로부터 90일로 계산합니다. 그러면 시간이 epoch 형식으로 변환되고 TTL 속성에 정수 데이터 유형으로 저장됩니다.

다음 코드 예제는 TTL로 항목을 만드는 방법을 보여줍니다.

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

**SDK for Java 2.x**  

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

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

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

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

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

    private final DynamoDbClient dynamoDbClient;

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

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

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

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

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

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

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

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

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

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

        try {
            final PutItemResponse response = dynamoDbClient.putItem(request);
            System.out.println(String.format(SUCCESS_MESSAGE, tableName));
            return response;
        } catch (ResourceNotFoundException e) {
            System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
            throw e;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            throw e;
        }
    }
}
```
+  API 세부 정보는 *AWS SDK for Java 2.x API 참조*의 [PutItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/PutItem)을 참조하세요.

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

**SDK for JavaScript(v3)**  

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

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

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

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

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

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

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

// Example usage (commented out for testing)
// createDynamoDBItem('your-table-name', 'us-east-1', 'your-partition-key-value', 'your-sort-key-value');
```
+  API 세부 정보는 *AWS SDK for JavaScript API 참조*의 [PutItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/PutItemCommand)을 참조하세요.

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

**SDK for Python(Boto3)**  

```
from datetime import datetime, timedelta

import boto3


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

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

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

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

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

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


# Use your own values
create_dynamodb_item(
    "your-table-name", "us-west-2", "your-partition-key-value", "your-sort-key-value"
)
```
+  API 세부 정보는 *AWS SDK for Python (Boto3) API 참조*의 [PutItem](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/PutItem)를 참조하세요.

------

## 항목 업데이트 및 Time to Live 새로 고침
<a name="time-to-live-ttl-before-you-start-update"></a>

이 예시는 [이전 섹션](#time-to-live-ttl-before-you-start-create)의 예시에서 이어집니다. 항목이 업데이트되면 만료 시간을 다시 계산할 수 있습니다. 다음 예시에서는 `expireAt` 타임스탬프를 현재 시간으로부터 90일이 되도록 다시 계산합니다.

다음 코드 예제에서는 항목의 TTL을 업데이트하는 방법을 보여줍니다.

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

**SDK for Java 2.x**  
테이블의 기존 DynamoDB 항목에서 TTL을 업데이트합니다.  

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.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 참조*의 [UpdateItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateItem)을 참조하세요.

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

**SDK for JavaScript(v3)**  

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

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

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

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

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

// Example usage (commented out for testing)
// updateItem('your-table-name', 'your-partition-key-value', 'your-sort-key-value');
```
+  API 세부 정보는 *AWS SDK for JavaScript API 참조*의 [UpdateItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/UpdateItemCommand)을 참조하세요.

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

**SDK for Python(Boto3)**  

```
from datetime import datetime, timedelta

import boto3


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

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

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

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

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


# Replace with your own values
update_dynamodb_item(
    "your-table-name", "us-west-2", "your-partition-key-value", "your-sort-key-value"
)
```
+  API 세부 정보는 *AWS SDK for Python (Boto3) API 참조*의 [UpdateItem](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/UpdateItem)를 참조하세요.

------

이 소개에서 설명하는 TTL 예시는 최근에 업데이트된 항목만 테이블에 보관하도록 하는 방법을 보여줍니다. 업데이트된 항목은 수명이 연장되는 반면, 업데이트되지 않은 항목은 생성 후 만료되고 비용 없이 삭제되므로 스토리지에서 차지하는 공간이 줄어들고 테이블이 정리됩니다.

# 만료된 항목 및 TTL(Time To Live) 작업
<a name="ttl-expired-items"></a>

삭제 보류 중인 만료된 항목은 읽기 및 쓰기 작업에서 필터링할 수 있습니다. 이는 만료된 데이터가 더 이상 유효하지 않아 사용해서는 안 되는 시나리오에서 유용합니다. 필터링되지 않은 경우 백그라운드 프로세스에서 삭제될 때까지 읽기 및 쓰기 작업에 계속 표시됩니다.

**참고**  
이러한 항목은 삭제되기 전까지는 여전히 스토리지 및 읽기 비용에 포함됩니다.

TTL 삭제는 DynamoDB Streams에서 식별할 수 있지만 삭제가 발생한 리전에서만 식별할 수 있습니다. 글로벌 테이블 리전에 복제된 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`)로 가져와서 epoch 시간 형식의 경우 `int`로 변환하는 할당 문이 포함되어 있습니다.

다음 코드 예제는 TTL 항목을 쿼리하는 방법을 보여줍니다.

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

**SDK for Java 2.x**  
필터링된 표현식을 쿼리하여 AWS SDK for Java 2.x를 사용해 DynamoDB 테이블에서 TTL 항목을 수집합니다.  

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

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

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

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

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

            return 0;
        } catch (ResourceNotFoundException e) {
            System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
            throw e;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            throw e;
        }
```
+  API 세부 정보는 *AWS SDK for Java 2.x API 참조*의 [Query](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/Query)를 참조하세요.

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

**SDK for JavaScript(v3)**  
필터링된 표현식을 쿼리하여 AWS SDK for JavaScript를 사용해 DynamoDB 테이블에서 TTL 항목을 수집합니다.  

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

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

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

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

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

// Example usage (commented out for testing)
// queryFiltered('your-table-name', 'your-partition-key-value');
```
+  API 세부 정보는 *AWS SDK for JavaScript API 참조*의 [Query](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/QueryCommand)를 참조하세요.

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

**SDK for Python(Boto3)**  
필터링된 표현식을 쿼리하여 AWS SDK for Python (Boto3)를 사용해 DynamoDB 테이블에서 TTL 항목을 수집합니다.  

```
from datetime import datetime

import boto3


def query_dynamodb_items(table_name, partition_key):
    """

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

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

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

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

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

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


# Call the function with your values
query_dynamodb_items("Music", "your-partition-key-value")
```
+  API 세부 정보는 *AWS SDK for Python (Boto3) API 참조*의 [Query](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/Query)를 참조하세요.

------

## 만료된 항목에 조건부 쓰기
<a name="ttl-expired-items-conditional-write"></a>

조건식을 사용하면 만료된 항목에 대한 쓰기를 방지할 수 있습니다. 아래 코드 스니펫은 만료 시간이 현재 시간보다 큰지를 확인하는 조건부 업데이트입니다. true인 경우 쓰기 작업이 계속됩니다.

다음 코드 예제는 항목의 TTL을 조건부로 업데이트하는 방법을 보여줍니다.

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

**SDK for Java 2.x**  
조건을 사용하여 테이블의 기존 DynamoDB 항목에서 TTL을 업데이트합니다.  

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

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

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

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

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

    private final DynamoDbClient dynamoDbClient;

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

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

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

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

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

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

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

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

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

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

        try (DynamoDbClient ddb = dynamoDbClient != null
            ? dynamoDbClient
            : DynamoDbClient.builder().region(region).build()) {
            final UpdateItemResponse response = ddb.updateItem(request);
            System.out.println(String.format(SUCCESS_MESSAGE, tableName));
            return 0;
        } catch (ConditionalCheckFailedException e) {
            System.err.println(CONDITION_FAILED_MESSAGE);
            throw e;
        } catch (ResourceNotFoundException e) {
            System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
            throw e;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            throw e;
        }
    }
}
```
+  API 세부 정보는 *AWS SDK for Java 2.x API 참조*의 [UpdateItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateItem)을 참조하세요.

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

**SDK for JavaScript(v3)**  
조건을 사용하여 테이블의 기존 DynamoDB 항목에서 TTL을 업데이트합니다.  

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

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

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

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

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

// Example usage (commented out for testing)
// updateItemConditional('your-table-name', 'your-partition-key-value', 'your-sort-key-value');
```
+  API 세부 정보는 *AWS SDK for JavaScript API 참조*의 [UpdateItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/UpdateItemCommand)을 참조하세요.

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

**SDK for Python(Boto3)**  
조건을 사용하여 테이블의 기존 DynamoDB 항목에서 TTL을 업데이트합니다.  

```
from datetime import datetime, timedelta

import boto3
from botocore.exceptions import ClientError


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

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

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

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

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

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

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

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


# replace with your values
update_dynamodb_item_ttl(
    "your-table-name",
    "us-east-1",
    "your-partition-key-value",
    "your-sort-key-value",
    "your-ttl-attribute-value",
)
```
+  API 세부 정보는 *AWS SDK for Python (Boto3) API 참조*의 [UpdateItem](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/UpdateItem)를 참조하세요.

------

## DynamoDB Streams에서 삭제된 항목 식별
<a name="ttl-expired-items-identifying"></a>

스트림 레코드에는 사용자 ID 필드 `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는 정렬된 순서대로 항목을 가져온 다음 `FilterExpression`과 모든 `KeyConditionExpression`(있는 경우)을 사용해 항목을 처리합니다. 그러면 클라이언트에게는 `Query` 결과만 다시 보내집니다.

`Query` 작업은 항상 결과 집합을 반환합니다. 일치하는 항목이 없다면 결과 집합은 비어 있습니다.

`Query` 결과는 항상 정렬 키 값을 기준으로 정렬됩니다. 정렬 키의 데이터 형식이 `Number`이면 결과가 숫자 순서대로 반환됩니다. 그렇지 않으면 결과가 UTF-8 바이트 순서로 반환됩니다. 기본적으로 정렬 순서는 오름차순입니다. 오름차순을 역순으로 바꾸려면 `ScanIndexForward` 파라미터를 `false`로 설정하면 됩니다.

단일 `Query` 작업은 최대 1MB의 데이터를 가져올 수 있습니다. 이러한 크기 제한은 `FilterExpression` 또는 `ProjectionExpression`이 결과에 반영되기 전에 적용됩니다. 응답에 `LastEvaluatedKey`가 존재하고 null이 아니라면 결과 집합을 페이지 매김해야 합니다([DynamoDB의 테이블 쿼리 결과 페이지 매김](Query.Pagination.md) 참조).

## 키 조건 표현식 예제
<a name="Query.KeyConditionExpressions-example"></a>

검색 기준을 지정하려면 테이블 또는 인덱스에서 읽을 항목을 결정하는 문자열인 *키 조건 표현식*을 사용합니다.

파티션 키 이름 및 값은 등식 조건으로 지정해야 합니다. 키 조건 표현식에는 키가 아닌 속성을 사용할 수 없습니다.

정렬 키의 두 번째 조건(있는 경우)은 옵션으로 입력할 수 있습니다. 단, 정렬 키 조건은 다음 중 한 가지 비교 연산자를 사용해야 합니다.
+ `a = b` - 속성 *a*가 값 *b*와 같은 경우 true
+ `a < b` - *a*가 *b*보다 작은 경우 true
+ `a <= b` - *a*가 *b*보다 작거나 같은 경우 true
+ `a > b` - *a*가 *b*보다 큰 경우 true
+ `a >= b` - *a*가 *b*보다 크거나 같은 경우 true
+ `a BETWEEN b AND c` - *a*가 *b*보다 크거나 같고 *c*보다 작거나 같은 경우 true

다음 함수도 지원됩니다.
+ `begins_with (a, substr)` - `a` 속성 값이 특정 하위 문자열로 시작하는 경우 true

다음 AWS Command Line Interface(AWS CLI) 예제는 키 조건 표현식의 사용을 보여 줍니다. 이 표현식들은 실제 값이 아닌 자리 표시자(`:name` 및 `:sub`)를 사용합니다. 자세한 내용은 [DynamoDB의 표현식 속성 이름(별칭)](Expressions.ExpressionAttributeNames.md) 및 [DynamoDB에서 표현식 속성 값 사용](Expressions.ExpressionAttributeValues.md) 단원을 참조하세요.

**Example**  
`Thread` 테이블에 대한 쿼리를 실행하여 특정 `ForumName`(파티션 키)을 찾습니다. 쿼리 결과에 따라 `ForumName` 값을 갖는 항목을 모두 읽어옵니다. 정렬 키(`Subject`)가 `KeyConditionExpression`에 추가되지 않았기 때문입니다.  

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

**Example**  
`Thread` 테이블에 대한 쿼리를 실행하여 특정 `ForumName`(파티션 키)을 찾습니다. 하지만 이번에는 `Subject`(정렬 키)를 갖는 항목만 반환됩니다.  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :name and Subject = :sub" \
    --expression-attribute-values  file://values.json
```
`--expression-attribute-values`의 인수는 `values.json` 파일에 저장됩니다.  

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

**Example**  
`Reply` 테이블에 대해 쿼리를 실행하여 특정 `Id`(파티션 키)를 찾습니다. 하지만 `ReplyDateTime`(정렬 키)이 몇 가지 문자로 시작되는 항목만 반환됩니다.  

```
aws dynamodb query \
    --table-name Reply \
    --key-condition-expression "Id = :id and begins_with(ReplyDateTime, :dt)" \
    --expression-attribute-values  file://values.json
```
`--expression-attribute-values`의 인수는 `values.json` 파일에 저장됩니다.  

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

# DynamoDB에서의 쿼리 작업에 대한 필터 표현식
<a name="Query.FilterExpression"></a>

`Query` 결과를 한층 더 좁혀야 하는 경우 선택적으로 필터 표현식을 제공할 수 있습니다. *필터 표현식*은 `Query` 결과 내에서 어떤 항목을 반환할지를 결정합니다. 다른 모든 결과는 폐기됩니다.

필터 표현식은 `Query`이 완료된 후 결과가 반환되기 전에 적용됩니다. 따라서 필터 표현식이 있는지 여부와 상관없이 `Query`은 동일한 양의 읽기 용량을 사용합니다.

`Query` 작업은 최대 1MB의 데이터를 가져올 수 있습니다. 이 제한은 필터 표현식이 평가되기 전에 적용됩니다.

필터 표현식에는 파티션 키 또는 정렬 키 속성이 포함될 수 없습니다. 필터 표현식이 아닌 키 조건 표현식에 있는 속성을 지정해야 합니다.

필터 표현식의 구문은 키 조건 표현식의 구문과 유사합니다. 필터 표현식에는 키 조건 표현식과 동일한 비교기, 함수 및 논리적 연산자를 사용할 수 있습니다. 또한 필터 표현식에는 같지 않음 연산자(`<>`), `OR` 연산자, `CONTAINS` 연산자, `IN` 연산자, `BEGINS_WITH` 연산자, `BETWEEN` 연산자, `EXISTS` 연산자 및 `SIZE` 연산자를 사용할 수 있습니다. 자세한 내용은 [DynamoDB에서의 쿼리 작업에 대한 키 조건 표현식](Query.KeyConditionExpressions.md) 및 [필터 및 조건 표현식 구문](Expressions.OperatorsAndFunctions.md#Expressions.OperatorsAndFunctions.Syntax) 단원을 참조하세요.

**Example**  
다음 AWS CLI 예제에서는 `Thread` 테이블에 대해 쿼리를 실행하여 특정 `ForumName`(파티션 키)과 `Subject`(정렬 키)를 찾아봅니다. 찾은 항목 중에서 가장 인기 있는 토론 스레드가 반환됩니다. 즉, 일정 수 이상의 `Views`가 있는 스레드만 반환됩니다.  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :fn and Subject begins_with :sub" \
    --filter-expression "#v >= :num" \
    --expression-attribute-names '{"#v": "Views"}' \
    --expression-attribute-values file://values.json
```
`--expression-attribute-values`의 인수는 `values.json` 파일에 저장됩니다.  

```
{
    ":fn":{"S":"Amazon DynamoDB"},
    ":sub":{"S":"DynamoDB Thread 1"},
    ":num":{"N":"3"}
}
```
`Views`는 DynamoDB에서 예약어이므로([DynamoDB의 예약어](ReservedWords.md) 참조) 이 예제에서는 `#v`를 자리 표시자로 사용합니다. 자세한 내용은 [DynamoDB의 표현식 속성 이름(별칭)](Expressions.ExpressionAttributeNames.md) 섹션을 참조하세요.

**참고**  
필터 표현식은 `Query` 결과 집합에서 항목을 제거합니다. 많은 수의 항목을 반환할 것으로 예상되지만 해당 항목 중 대부분을 폐기해야 하는 경우 가능하다면 `Query`를 사용하지 마세요.

# DynamoDB의 테이블 쿼리 결과 페이지 매김
<a name="Query.Pagination"></a>

DynamoDB는 `Query` 작업 결과의 *페이지를 매깁니다*. 페이지를 매기면 `Query` 결과는 크기가 1MB 이하인 데이터 ‘페이지’로 분리됩니다. 애플리케이션은 결과의 첫 번째 페이지를 처리한 다음 두 번째 페이지를 처리하고 이런 식으로 계속할 수 있습니다.

단일 `Query`는 1MB 크기 한도 내에 맞는 결과 집합만 반환합니다. 추가 결과가 있는지 확인하고 이러한 결과를 한번에 한 페이지에 가져오려면 애플리케이션에서 다음을 수행해야 합니다.

1. 하위 수준 `Query` 결과를 확인합니다.
   + 결과가 `LastEvaluatedKey` 요소를 포함하고 null이 아닌 경우 2단계로 계속합니다.
   + 결과에 `LastEvaluatedKey`가 *없는* 경우 더 이상 가져올 항목이 없습니다.

1. 동일한 `KeyConditionExpression`을 사용하여 `Query`를 구성합니다. 그러나 이번에는 1단계에서 `LastEvaluatedKey` 값을 가져와서 새로운 `ExclusiveStartKey` 요청의 `Query` 파라미터로 사용합니다.

1. 새로운 `Query` 요청을 실행합니다.

1. 1단계로 이동합니다.

다시 말해서, `LastEvaluatedKey` 응답의 `Query`를 다음 `ExclusiveStartKey` 요청에 대한 `Query`로 사용해야 합니다. `LastEvaluatedKey` 응답에 `Query` 요소가 없는 경우 결과의 최종 페이지를 검색한 것입니다. `LastEvaluatedKey`가 비어 있지 않는 경우 결과 집합에 데이터가 더 있음을 의미하는 것은 아닙니다. 결과 집합의 마지막 페이지를 알 수 있는 유일한 방법은 `LastEvaluatedKey`가 비어 있을 때입니다.

AWS CLI를 사용하여 이 동작을 볼 수 있습니다. AWS CLI는 `LastEvaluatedKey`가 결과에 더 이상 없을 때까지 하위 수준 `Query` 요청을 DynamoDB에 반복적으로 보냅니다. 특정 연도의 영화 제목을 검색하는 다음 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 SDK는 하위 수준 DynamoDB 응답(`LastEvaluatedKey`의 유무 포함)을 처리하여 `Query` 결과 페이지 매김에 대해 다양한 추상을 제공합니다. 예를 들어, SDK for Java 문서 인터페이스는 `java.util.Iterator` 지원을 제공하므로 한 번에 하나씩 결과를 볼 수 있습니다.  
다양한 프로그래밍 언어의 코드 예제를 보려면 [Amazon DynamoDB 시작 안내서](https://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/) 및 해당 언어의 AWS SDK 설명서를 참조하세요.

`Query` 작업의 `Limit` 파라미터를 사용하여 결과 세트의 항목 수를 제한하여 페이지 크기를 줄일 수도 있습니다.

DynamoDB를 사용한 쿼리 방법에 대한 자세한 내용은 [DynamoDB에서 테이블 쿼리](Query.md) 단원을 참조하세요.

# DynamoDB에서의 쿼리 작업에 대한 기타 측면
<a name="Query.Other"></a>

이 섹션에서는 결과 크기 제한, 스캔된 항목과 반환된 항목 수 계산 비교, 읽기 용량 소비 모니터링, 읽기 일관성 제어 등 DynamoDB 쿼리 작업의 추가 측면을 다룹니다.

## 결과 세트의 항목 수 제한
<a name="Query.Limit"></a>

`Query` 작업을 사용하여 읽는 항목 수를 제한할 수 있습니다. 이렇게 하려면 `Limit` 파라미터를 원하는 최대 항목 수로 설정합니다.

예를 들어 `Query` 값이 `Limit`이고 필터 표현식이 없는 상태에서 테이블을 `6`한다고 가정합니다. `Query` 결과에는 테이블에서 요청의 키 조건 표현식과 일치하는 처음 6개의 항목이 포함됩니다.

이제 필터 표현식을 `Query`에 추가한다고 가정합니다. 이 경우 DynamoDB는 최대 6개의 항목을 읽은 다음 필터 표현식과 일치하는 항목만 반환합니다. DynamoDB에서 더 많은 항목을 계속 읽은 경우 필터 표현식과 일치하는 항목이 더 많더라도 최종 `Query` 결과에는 여섯 개 이하의 항목이 포함됩니다.

## 결과 내 항목 수 계산
<a name="Query.Count"></a>

`Query` 응답에는 기준과 일치하는 항목 외에도 다음 요소가 포함됩니다.
+ `ScannedCount` - 필터 표현식(있는 경우)을 적용하기 *전*에 키 조건 표현식과 일치한 항목 수입니다.
+ `Count` - 필터 표현식(있는 경우)을 적용한 *후*에 남아 있는 항목 수입니다.

**참고**  
필터 표현식을 사용하지 않으면 `ScannedCount`와 `Count`는 동일한 값을 갖습니다.

`Query` 결과 집합의 크기가 1MB보다 크면 `ScannedCount`와 `Count`는 총 항목 수의 일부만 표시합니다. 모든 결과를 검색하려면 여러 `Query` 작업을 수행해야 합니다([DynamoDB의 테이블 쿼리 결과 페이지 매김](Query.Pagination.md) 참조).

각 `Query` 응답에는 해당하는 특정 `ScannedCount` 요청에 따라 처리된 항목의 `Count`와 `Query`가 포함됩니다. 모든 `Query` 요청의 총계를 얻으려면 `ScannedCount`와 `Count`의 누계를 계산할 수 있습니다.

## 쿼리에서 사용된 용량 단위
<a name="Query.CapacityUnits"></a>

파티션 키 속성의 이름과 해당 속성의 단일 값을 제공하기만 하면 모든 테이블 또는 보조 인덱스를 `Query`할 수 있습니다. `Query`는 해당 파티션 키 값을 갖는 모든 항목을 반환합니다. 필요에 따라 정렬 키 속성을 제공하고 비교 연산자를 사용하여 검색 결과의 범위를 좁힐 수 있습니다. `Query` API 작업은 다음과 같은 읽기 용량 단위를 사용합니다.


****  

| 다음을 `Query`하는 경우... | DynamoDB는 다음에서 읽기 용량 단위를 사용합니다... | 
| --- | --- | 
| 표 | 테이블의 할당된 읽기 용량. | 
| 글로벌 보조 인덱스 | 인덱스의 할당된 읽기 용량. | 
| 로컬 보조 인덱스 | 기본 테이블의 프로비저닝된 읽기 용량. | 

기본적으로, `Query` 작업은 얼마나 많은 읽기 용량을 사용하는지에 대한 데이터를 반환하지 않습니다. 하지만 `ReturnConsumedCapacity` 요청에서 `Query` 파라미터를 지정하여 이 정보를 얻을 수 있습니다. 다음은 `ReturnConsumedCapacity`에 대한 유효한 설정입니다.
+ `NONE` - 사용된 용량 데이터가 반환되지 않습니다. (이 값이 기본값입니다.)
+ `TOTAL` - 사용된 읽기 용량 단위의 집계 수가 응답에 포함됩니다.
+ `INDEXES` - 액세스한 각 테이블 및 인덱스에 사용된 용량과 함께 사용된 읽기 용량 단위의 집계 수가 응답에 표시됩니다.

DynamoDB는 애플리케이션에 반환되는 데이터 양이 아닌 항목 개수와 항목 크기를 기준으로 사용된 읽기 용량 단위의 수를 계산합니다. 이러한 이유로, 모든 속성을 요청하든(기본 동작) 또는 일부 속성만 요청하든(프로젝션 표현식 사용) 상관없이 사용된 용량 단위의 수는 동일합니다. 필터 표현식 사용 여부와 관계없이 숫자는 동일합니다. `Query`는 최대 4KB의 항목에 대해 초당 강력히 일관된 읽기 1회 또는 초당 최종적으로 일관된 읽기 2회를 수행하기 위해 최소한의 읽기 용량 단위를 사용합니다. 보다 큰 항목을 읽어야 하는 경우, 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` 요청으로 최대 1MB의 데이터를 가져올 수 있습니다. 선택에 따라 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` 작업은 최대 1MB의 데이터를 가져올 수 있습니다. 이 제한은 필터 표현식이 평가되기 전에 적용됩니다.

`Scan`을 사용하면 필터 표현식에 파티션 키와 정렬 키 속성을 포함하여 모든 속성을 지정할 수 있습니다.

필터 표현식의 구분은 조건 표현식의 구문과 같습니다. 필터 표현식은 동일한 비교기, 함수 및 논리적 연산자를 조건 표현식으로 사용할 수 있습니다. 논리 연산자에 대한 자세한 내용은 [DynamoDB의 조건 및 필터 표현식, 연산자, 함수](Expressions.OperatorsAndFunctions.md) 섹션을 참조하세요.

**Example**  
다음 AWS Command Line Interface(AWS CLI) 예제에서는 `Thread` 테이블을 스캔하여 특정 사용자가 마지막으로 게시한 항목만 반환합니다.  

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

## 결과 세트의 항목 수 제한
<a name="Scan.Limit"></a>

`Scan` 작업을 사용하여 결과에 반환되는 항목 수를 제한할 수 있습니다. 이렇게 하려면 필터 표현식 평가 전에 `Limit` 파라미터를 `Scan` 작업에서 반환할 최대 항목 수로 설정합니다.

예를 들어 `Scan` 값이 `Limit`이고 필터 표현식이 없는 상태에서 테이블을 `6`한다고 가정합니다. `Scan` 결과에 테이블의 처음 6개 항목이 포함됩니다.

이제 필터 표현식을 `Scan`에 추가한다고 가정합니다. 이 경우 DynamoDB는 반환된 6개 항목에 필터 표현식을 적용하고 일치하지 않는 항목을 무시합니다. 최종 `Scan` 결과에는 필터링된 항목 수에 따라 6개 이하의 항목이 포함됩니다.

## 결과 페이지 매김
<a name="Scan.Pagination"></a>

DynamoDB는 `Scan` 작업 결과의 *페이지를 매깁니다*. 페이지를 매기면 `Scan` 결과는 크기가 1MB 이하인 데이터 ‘페이지’로 분리됩니다. 애플리케이션은 결과의 첫 번째 페이지를 처리한 다음 두 번째 페이지를 처리하고 이런 식으로 계속할 수 있습니다.

단일 `Scan`은 1MB 크기 한도 내에 맞는 결과 집합만 반환합니다.

추가 결과가 있는지 확인하고 이러한 결과를 한번에 한 페이지에 가져오려면 애플리케이션에서 다음을 수행해야 합니다.

1. 하위 수준 `Scan` 결과를 확인합니다.
   + 결과에 `LastEvaluatedKey` 요소가 포함되는 경우 2단계로 계속합니다.
   + 결과에 `LastEvaluatedKey`가 *없는* 경우 더 이상 가져올 항목이 없습니다.

1. 이전과 동일한 파라미터를 이용해 새로운 `Scan` 요청을 구성합니다. 그러나 이번에는 1단계에서 `LastEvaluatedKey` 값을 가져와서 새로운 `ExclusiveStartKey` 요청의 `Scan` 파라미터로 사용합니다.

1. 새로운 `Scan` 요청을 실행합니다.

1. 1단계로 이동합니다.

다시 말해서, `LastEvaluatedKey` 응답의 `Scan`를 다음 `ExclusiveStartKey` 요청에 대한 `Scan`로 사용해야 합니다. `LastEvaluatedKey` 응답에 `Scan` 요소가 없는 경우 결과의 최종 페이지를 검색한 것입니다. 결과 집합의 마지막에 도달했음을 알 수 있는 유일한 방법은 `LastEvaluatedKey`가 없는지 확인하는 것입니다.

AWS CLI를 사용하여 이 동작을 볼 수 있습니다. AWS CLI는 `LastEvaluatedKey`가 결과에 더 이상 없을 때까지 하위 수준 `Scan` 요청을 DynamoDB에 반복적으로 보냅니다. 전체 AWS CLI 테이블을 스캔하여 특정 장르의 영화만 반환하는 다음 `Movies` 예제를 살펴보겠습니다.

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

일반적으로 AWS CLI에서는 페이지 매김이 자동으로 처리됩니다. 그러나 이 예제에서는 AWS CLI `--page-size` 파라미터가 페이지당 항목 수를 제한합니다. `--debug` 파라미터는 요청 및 응답에 대한 하위 수준 정보를 출력합니다.

**참고**  
페이지 매김 결과는 전달한 입력 매개 변수에 따라 달라집니다.  
`aws dynamodb scan --table-name Prices --max-items 1` 사용 시 `NextToken`을(를) 반환합니다.
`aws dynamodb scan --table-name Prices --limit 1` 사용 시 `LastEvaluatedKey`을(를) 반환합니다.
특히 `--starting-token` 사용 시 `NextToken` 값이 필요하다는 점에 유의하세요.

예제를 실행하면 DynamoDB의 첫 응답이 다음과 유사합니다.

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

응답의 `LastEvaluatedKey`는 가져온 항목이 전부가 아님을 나타냅니다. 그러면 AWS CLI는 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 SDK는 하위 수준 DynamoDB 응답(`LastEvaluatedKey`의 유무 포함)을 처리하여 `Scan` 결과 페이지 매김에 대해 다양한 추상을 제공합니다. 예를 들어, SDK for Java 문서 인터페이스는 `java.util.Iterator` 지원을 제공하므로 한 번에 하나씩 결과를 볼 수 있습니다.  
다양한 프로그래밍 언어의 코드 예제를 보려면 [Amazon DynamoDB 시작 안내서](https://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/) 및 해당 언어의 AWS SDK 설명서를 참조하세요.

## 결과 내 항목 수 계산
<a name="Scan.Count"></a>

`Scan` 응답에는 기준과 일치하는 항목 외에도 다음 요소가 포함됩니다.
+ `ScannedCount` - `ScanFilter`를 적용하기 전에 평가되는 항목 수입니다. `ScannedCount` 값이 높지만 `Count` 결과가 거의 없거나 전혀 없는 경우 `Scan` 작업이 비효율적이라는 것을 나타냅니다. 요청에 필터를 사용하지 않은 경우 `ScannedCount`는 `Count`와 동일합니다.
+ `Count` - 필터 표현식(있는 경우)을 적용한 *후*에 남아 있는 항목 수입니다.

**참고**  
필터 표현식을 사용하지 않으면 `ScannedCount`와 `Count`는 동일한 값을 갖습니다.

`Scan` 결과 집합의 크기가 1MB보다 크면 `ScannedCount`와 `Count`는 총 항목 수의 일부만 표시합니다. 모든 결과를 검색하려면 여러 `Scan` 작업을 수행해야 합니다([결과 페이지 매김](#Scan.Pagination) 참조).

각 `Scan` 응답에는 해당하는 특정 `ScannedCount` 요청에 따라 처리된 항목의 `Count`와 `Scan`가 포함됩니다. 모든 `Scan` 요청의 총계를 가져오려면 `ScannedCount`와 `Count`의 누계를 계산할 수 있습니다.

## 스캔에서 사용된 용량 단위
<a name="Scan.CapacityUnits"></a>

테이블이나 보조 인덱스를 `Scan`할 수 있습니다. `Scan` 작업은 다음과 같이 읽기 용량 단위를 사용합니다.


****  

| 다음을 `Scan`하는 경우... | DynamoDB는 다음에서 읽기 용량 단위를 사용합니다... | 
| --- | --- | 
| 표 | 테이블의 할당된 읽기 용량. | 
| 글로벌 보조 인덱스 | 인덱스의 할당된 읽기 용량. | 
| 로컬 보조 인덱스 | 기본 테이블의 프로비저닝된 읽기 용량. | 

**참고**  
보조 인덱스 스캔 작업에 대한 교차 계정 액세스는 현재 [리소스 기반 정책](access-control-resource-based.md)에서 지원되지 않습니다.

기본적으로, `Scan` 작업은 얼마나 많은 읽기 용량을 사용하는지에 대한 데이터를 반환하지 않습니다. 하지만 `ReturnConsumedCapacity` 요청에서 `Scan` 파라미터를 지정하여 이 정보를 얻을 수 있습니다. 다음은 `ReturnConsumedCapacity`에 대한 유효한 설정입니다.
+ `NONE` - 사용된 용량 데이터가 반환되지 않습니다. (이 값이 기본값입니다.)
+ `TOTAL` - 사용된 읽기 용량 단위의 집계 수가 응답에 포함됩니다.
+ `INDEXES` - 액세스한 각 테이블 및 인덱스에 사용된 용량과 함께 사용된 읽기 용량 단위의 집계 수가 응답에 표시됩니다.

DynamoDB는 애플리케이션에 반환되는 데이터 양이 아닌 항목 개수와 항목 크기를 기준으로 사용된 읽기 용량 단위의 수를 계산합니다. 이러한 이유로, 모든 속성을 요청하든(기본 동작) 또는 일부 속성만 요청하든(프로젝션 표현식 사용) 상관없이 사용된 용량 단위의 수는 동일합니다. 필터 표현식 사용 여부와 관계없이 숫자는 동일합니다. `Scan`는 최대 4KB의 항목에 대해 초당 강력히 일관된 읽기 1회 또는 초당 최종적으로 일관된 읽기 2회를 수행하기 위해 최소한의 읽기 용량 단위를 사용합니다. 보다 큰 항목을 읽어야 하는 경우, DynamoDB에 추가 읽기 요청 단위가 필요합니다. 파티션 키의 양이 적은 빈 테이블과 매우 큰 테이블에서는 스캔된 데이터 양을 초과하여 일부 추가 RCU에 요금이 부과될 수 있습니다. 여기에는 데이터가 없는 경우에도 `Scan` 요청을 처리하는 데 드는 비용이 포함됩니다.

## 스캔에 대한 읽기 정합성
<a name="Scan.ReadConsistency"></a>

기본적으로 `Scan` 작업은 최종적 일관된 읽기를 수행합니다. 따라서 최근 완료된 `Scan` 또는 `PutItem` 작업으로 인해 `UpdateItem` 결과에 변경 사항이 반영되지 않을 수 있습니다. 자세한 내용은 [DynamoDB 읽기 일관성](HowItWorks.ReadConsistency.md) 섹션을 참조하세요.

`Scan`이 시작되는 시점을 기준으로 강력한 일관된 읽기가 필요한 경우 `ConsistentRead` 요청에서 `true` 파라미터를 `Scan`로 설정합니다. 그러면 `Scan` 작업 시작 전에 마친 쓰기 작업까지 모두 `Scan` 응답에 포함됩니다.

`ConsistentRead`를 `true`로 설정하면 [DynamoDB Streams](./Streams.html)를 함께 사용하는 테이블 백업 또는 복제 시나리오에서 유용할 수 있습니다. 처음에는 `Scan`을 true로 설정한 상태에서 `ConsistentRead`를 사용하여 테이블 데이터에 대한 일관된 복사본을 얻습니다. 그러면 DynamoDB Streams가 `Scan` 작업 중에 테이블에서 추가로 발행하는 쓰기 활동을 기록합니다. `Scan` 작업을 마치면 스트림의 쓰기 연산을 테이블에 적용할 수 있습니다.

**참고**  
`Scan`를 `ConsistentRead`로 설정한 상태에서 `true` 작업을 수행하면 `ConsistentRead`를 기본값(`false`)으로 그대로 두는 경우와 비교할 때 2배 더 많은 읽기 용량 단위를 사용합니다.

## 병렬 스캔
<a name="Scan.ParallelScan"></a>

기본적으로 `Scan` 작업은 데이터를 순차적으로 처리합니다. Amazon DynamoDB는 애플리케이션에 1MB 단위로 데이터를 반환하고 애플리케이션은 추가 `Scan` 작업을 수행하여 다음 1MB의 데이터를 가져옵니다.

스캔할 테이블 또는 인덱스가 클수록 `Scan`을 완료하는 데 걸리는 시간이 늘어납니다. 또한 순차적 `Scan`은 프로비저닝된 읽기 처리 용량을 항상 최대한 사용할 수 있는 것은 아닙니다. DynamoDB가 여러 물리적 파티션 간에 큰 테이블 데이터를 분산해도 `Scan` 작업은 한 번에 한 파티션만 읽을 수 있습니다. 이러한 이유로 `Scan`의 처리량은 단일 파티션의 최대 처리량에 따라 제약을 받습니다.

이 문제를 해결하기 위해 `Scan` 작업에서는 테이블 또는 보조 인덱스를 여러 *세그먼트*로 논리적으로 나눠 여러 애플리케이션 작업자가 세그먼트를 병렬로 처리하도록 할 수 있습니다. 각 작업자는 스레드(멀티스레딩을 지원하는 프로그래밍 언어에서) 또는 운영 체제 프로세스일 수 있습니다. 병렬 스캔을 수행하려면 각 작업자가 다음 파라미터를 사용하여 `Scan` 요청을 발행합니다.
+ `Segment` - 특정 작업자가 스캔할 세그먼트입니다. 각 작업자는 `Segment`에 서로 다른 값을 사용해야 합니다.
+ `TotalSegments` - 병렬 스캔에 사용되는 총 세그먼트 수입니다. 이 값은 애플리케이션에서 사용할 작업자 수와 같아야 합니다.

다음 다이어그램은 멀티스레드 애플리케이션이 3 병렬 처리 수준을 사용하여 병렬 `Scan`을 수행하는 방법에 대해 설명합니다.

![\[테이블을 3개의 세그먼트로 나누어 병렬 스캔을 수행하는 다중 스레드 애플리케이션입니다.\]](http://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/images/ParallelScan.png)




이 다이어그램에서 애플리케이션은 세 개의 스레드를 생성하여 각 스레드에 번호를 지정합니다. (세그먼트는 0부터 시작하므로 첫 번째 번호는 항상 0입니다.) 각 스레드는 `Scan` 요청을 실행하며, `Segment`를 해당 지정 번호로 설정하고 `TotalSegments`를 3으로 설정합니다. 각 스레드는 해당 지정 세그먼트를 스캔하며 한 번에 1MB의 데이터를 가져와서 애플리케이션의 기본 스레드에 데이터를 반환합니다.

DynamoDB는 각 항목의 파티션 키에 해시 함수를 적용하여 항목을 *세그먼트*에 할당합니다. 지정된 `TotalSegments` 값의 경우 파티션 키가 동일한 모든 항목이 항상 동일한 `Segment`에 할당됩니다. 즉, *항목 1*, *항목 2* 및 *항목 3*이 모두 `pk="account#123"`을 공유하는 테이블에서(정렬 키는 다르지만) 이러한 항목은 정렬 키 값이나 *항목 컬렉션*의 크기에 관계없이 동일한 작업자가 처리합니다.

*세그먼트* 할당은 파티션 키 해시만을 기반으로 하기 때문에 세그먼트가 고르지 않게 분산될 수 있습니다. 일부 세그먼트에는 항목이 없을 수 있지만, 다른 세그먼트에는 큰 항목 컬렉션이 있는 많은 파티션 키가 포함될 수 있습니다. 따라서 총 세그먼트 수를 늘려도 특히 파티션 키가 키스페이스에 균일하게 분산되지 않는 경우 스캔 성능이 향상되지 않습니다.

`Segment` 및 `TotalSegments` 값을 개별 `Scan` 요청에 적용하여 언제든지 다른 값을 사용할 수 있습니다. 애플리케이션이 최적의 성능을 발휘하려면 이러한 값과 사용하는 작업자 수에 대한 여러 번의 시도가 필요할 수 있습니다.

**참고**  
작업자 수가 많은 병렬 스캔 작업은 스캔할 테이블 또는 인덱스에 대한 모든 할당된 처리량을 족히 소비할 수 있습니다. 테이블 또는 인덱스가 다른 애플리케이션에서 과도한 읽기 또는 쓰기 작업을 발생시키는 경우 이러한 스캔을 수행하지 않아야 합니다.  
요청당 반환되는 데이터 양을 제어하려면 `Limit` 파라미터를 사용하세요. 이를 사용하면 다른 모든 작업자가 이용할 비용으로 한 작업자가 할당된 모든 처리량을 소비하게 되는 상황을 방지할 수 있습니다.

# PartiQL - Amazon DynamoDB용 SQL 호환 쿼리 언어
<a name="ql-reference"></a>

Amazon DynamoDB에서는 SQL 호환 쿼리 언어인 [PartiQL](https://partiql.org/)을 사용하여 Amazon DynamoDB에서 데이터를 선택, 삽입, 업데이트, 삭제할 수 있습니다. PartiQL을 사용하면 DynamoDB 테이블과 쉽게 상호 작용하고 AWS Management Console, NoSQL Workbench, AWS Command Line Interface 및 PartiQL용 DynamoDB API를 사용하여 임시 쿼리를 실행할 수 있습니다.

PartiQL 작업은 다른 DynamoDB 데이터 영역 작업과 동일한 가용성, 대기 시간 및 성능을 제공합니다.

다음 단원에서는 PartiQL의 DynamoDB 구현을 설명합니다.

**Topics**
+ [PartiQL이란?](#ql-reference.what-is)
+ [Amazon DynamoDB의 PartiQL](#ql-reference.what-is)
+ [시작하기](ql-gettingstarted.md)
+ [데이터 타입](ql-reference.data-types.md)
+ [문](ql-reference.statements.md)
+ [함수](ql-functions.md)
+ [연산자](ql-operators.md)
+ [트랜잭션](ql-reference.multiplestatements.transactions.md)
+ [배치 작업](ql-reference.multiplestatements.batching.md)
+ [IAM 정책](ql-iam.md)

## PartiQL이란?
<a name="ql-reference.what-is"></a>

*PartiQL*은 구조화 데이터, 반구조화 데이터 및 중첩 데이터를 포함하는 여러 데이터 스토어에서 SQL 호환 쿼리 액세스를 제공합니다. Amazon 내에서 널리 사용되며 현재 DynamoDB를 비롯한 여러 AWS 서비스의 일부로 제공됩니다.

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
+ 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 API를 사용하여 DynamoDB에 액세스하는 방법에 대한 자세한 내용은 [DynamoDB DB 액세스](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AccessingDynamoDB.html)를 참조하세요.

[NoSQL 워크벤치](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.html)를 [다운로드](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.settingup.html)하고 사용하여 [DynamoDB용 PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html) 문을 빌드하려면 DynamoDB용 NoSQL Workbench **작업 빌더(Operation Builder)** 오른쪽 맨 위에서 [PartiQL 작업(PartiQL operations)](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.querybuilder.operationbuilder.html)를 선택합니다.

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

![\[Music 테이블에 대한 Query 작업 실행 결과를 보여주는 PartiQL 에디터 인터페이스.\]](http://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/images/partiqlgettingstarted.png)


1. AWS Management Console에 로그인하고 [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)에서 DynamoDB 콘솔을 엽니다.

1. 콘솔 왼쪽의 탐색 창에서 **PartiQL editor(PartiQL 편집기)**를 선택합니다.

1. **Music** 테이블을 선택합니다.

1. **Query table(테이블 쿼리)**을 선택합니다. 이 작업을 수행하면 전체 테이블이 스캔되지 않는 쿼리가 생성됩니다.

1. `partitionKeyValue`를 문자열 값 `Acme Band`로 바꿉니다. `sortKeyValue`를 문자열 값 `Happy Day`로 바꿉니다.

1. **실행** 버튼을 선택합니다.

1. **Table view(테이블 보기)** 또는 **JSON view(JSON 보기)** 버튼을 선택하여 쿼리의 결과를 볼 수 있습니다.

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

![\[NoSQL Workbench 인터페이스. Music 테이블에 대해 실행할 수 있는 PartiQL SELECT 문을 보여줍니다.\]](http://docs.aws.amazon.com/ko_kr/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 parameter(새 파라미터 추가)**를 선택합니다.

   1. 속성 형식 **문자열**과 값 `Acme Band`를 선택합니다.

   1. b단계와 c단계를 반복하고 형식 **문자열**과 값 `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. DELETE PartiQL 문을 사용하여 `Music` 테이블에서 항목을 삭제합니다.

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

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

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

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

public class DynamoDBPartiQGettingStarted {

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

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

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

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

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

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

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

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

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

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

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

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

    private static AmazonDynamoDB createDynamoDbClient(String region) {
        return AmazonDynamoDBClientBuilder.standard().withRegion(region).build();
    }

    private static List<AttributeValue> getPartiQLParameters() {
        List<AttributeValue> parameters = new ArrayList<AttributeValue>();
        parameters.add(new AttributeValue("Acme Band"));
        parameters.add(new AttributeValue("PartiQL Rocks"));
        return parameters;
    }

    private static ExecuteStatementResult executeStatementRequest(AmazonDynamoDB client, String statement, List<AttributeValue> parameters ) {
        ExecuteStatementRequest request = new ExecuteStatementRequest();
        request.setStatement(statement);
        request.setParameters(parameters);
        return client.executeStatement(request);
    }

    private static void processResults(ExecuteStatementResult executeStatementResult) {
        System.out.println("ExecuteStatement successful: "+ executeStatementResult.toString());

    }

    // Handles errors during ExecuteStatement execution. Use recommendations in error messages below to add error handling specific to
    // your application use-case.
    private static void handleExecuteStatementErrors(Exception exception) {
        try {
            throw exception;
        } catch (ConditionalCheckFailedException ccfe) {
            System.out.println("Condition check specified in the operation failed, review and update the condition " +
                                       "check before retrying. Error: " + ccfe.getErrorMessage());
        } catch (TransactionConflictException tce) {
            System.out.println("Operation was rejected because there is an ongoing transaction for the item, generally " +
                                       "safe to retry with exponential back-off. Error: " + tce.getErrorMessage());
        } catch (ItemCollectionSizeLimitExceededException icslee) {
            System.out.println("An item collection is too large, you\'re using Local Secondary Index and exceeded " +
                                       "size limit of items per partition key. Consider using Global Secondary Index instead. Error: " + icslee.getErrorMessage());
        } catch (Exception e) {
            handleCommonErrors(e);
        }
    }

    private static void handleCommonErrors(Exception exception) {
        try {
            throw exception;
        } catch (InternalServerErrorException isee) {
            System.out.println("Internal Server Error, generally safe to retry with exponential back-off. Error: " + isee.getErrorMessage());
        } catch (RequestLimitExceededException rlee) {
            System.out.println("Throughput exceeds the current throughput limit for your account, increase account level throughput before " +
                                       "retrying. Error: " + rlee.getErrorMessage());
        } catch (ProvisionedThroughputExceededException ptee) {
            System.out.println("Request rate is too high. If you're using a custom retry strategy make sure to retry with exponential back-off. " +
                                       "Otherwise consider reducing frequency of requests or increasing provisioned capacity for your table or secondary index. Error: " +
                                       ptee.getErrorMessage());
        } catch (ResourceNotFoundException rnfe) {
            System.out.println("One of the tables was not found, verify table exists before retrying. Error: " + rnfe.getErrorMessage());
        } catch (AmazonServiceException ase) {
            System.out.println("An AmazonServiceException occurred, indicates that the request was correctly transmitted to the DynamoDB " +
                                       "service, but for some reason, the service was not able to process it, and returned an error response instead. Investigate and " +
                                       "configure retry strategy. Error type: " + ase.getErrorType() + ". Error message: " + ase.getErrorMessage());
        } catch (AmazonClientException ace) {
            System.out.println("An AmazonClientException occurred, indicates that the client was unable to get a response from DynamoDB " +
                                       "service, or the client was unable to parse the response from the service. Investigate and configure retry strategy. "+
                                       "Error: " + ace.getMessage());
        } catch (Exception e) {
            System.out.println("An exception occurred, investigate and configure retry strategy. Error: " + e.getMessage());
        }
    }

}
```

------

## 파라미터화된 문 사용
<a name="ql-gettingstarted.parameterized"></a>

PartiQL 문 문자열에 직접 값을 포함하는 대신 물음표(`?`) 자리 표시자를 사용하고 `Parameters` 필드에 값을 별도로 제공할 수 있습니다. 각 `?` 값은 제공된 순서대로 해당 파라미터 값으로 대체됩니다.

파라미터화된 문을 사용하는 것이 모범 사례입니다. 문 구조를 데이터 값과 분리하므로 문을 더 쉽게 읽고 재사용할 수 있기 때문입니다. 또한 명령문 문자열에서 속성 값을 수동으로 포맷하고 이스케이프할 필요가 없습니다.

파라미터화된 문은 `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/ko_kr/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 또는 API를 사용하여 수동으로 실행하는 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에서 트랜잭션 수행](ql-reference.multiplestatements.transactions.md) 및 [DynamoDB용 PartiQL에서 일괄 작업 실행](ql-reference.multiplestatements.batching.md)도 DynamoDB용 PartiQL에서 지원됩니다.

# DynamoDB의 PartiQL select 문
<a name="ql-reference.select"></a>

`SELECT` 문을 사용하면 Amazon DynamoDB의 테이블에서 데이터를 검색할 수 있습니다.

`SELECT` 문을 사용하면 WHERE 절에 파티션 키를 사용한 등식 또는 IN 조건을 지정하지 않은 경우 전체 테이블이 스캔될 수 있습니다. 스캔 작업은 요청한 값을 찾기 위해 전체 항목을 검사하기 때문에 대용량 테이블이나 인덱스일 경우에는 단 한 번의 작업으로 프로비저닝된 처리량을 모두 사용할 수 있습니다.

PartiQL에서 전체 테이블 스캔을 방지하려면 다음과 같이 할 수 있습니다.
+ [WHERE 절 조건](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.select.html#ql-reference.select.parameters)이 적절히 구성되도록 하여 전체 테이블이 스캔되지 않도록 `SELECT` 문을 작성합니다.
+ DynamoDB 개발자 안내서의 [예: DynamoDB용 PartiQL에서 select 문은 허용하고 전체 테이블 스캔 문은 거부](ql-iam.md#access-policy-ql-iam-example6) 단원에 지정된 IAM 정책을 사용하여 전체 테이블 스캔을 사용 중지합니다.

자세한 내용은 DynamoDB 개발자 안내서에서 [데이터 쿼리 및 검색 모범 사례](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-query-scan.html)를 참조하세요.

**Topics**
+ [구문](#ql-reference.select.syntax)
+ [파라미터](#ql-reference.select.parameters)
+ [예제](#ql-reference.select.examples)

## 구문
<a name="ql-reference.select.syntax"></a>

```
SELECT expression  [, ...] 
FROM table[.index]
[ WHERE condition ] [ [ORDER BY key [DESC|ASC] , ...]
```

## 파라미터
<a name="ql-reference.select.parameters"></a>

***expression***  
(필수) `*` 와일드카드에서 형성된 프로젝션 또는 결과 집합에 있는 하나 이상의 속성 이름 또는 문서 경로로 구성된 프로젝션 목록입니다. expression은 [DynamoDB에서 PartiQL 함수 사용](ql-functions.md)에 대한 호출 또는 [DynamoDB용 PartiQL 산술, 비교 및 논리 연산자](ql-operators.md)에서 수정되는 필드로 구성될 수 있습니다.

***테이블*\$1**  
(필수) 쿼리할 테이블 이름입니다.

*** 인덱스***  
(선택 사항) 쿼리할 인덱스의 이름입니다.  
인덱스를 쿼리할 때 테이블 이름과 인덱스 이름에 큰따옴표를 추가해야 합니다.  

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

*** 조건***  
(선택 사항) 쿼리의 선택 기준입니다.  
`SELECT` 문이 전체 테이블 스캔이 되지 않게 하려면 `WHERE` 절 조건에서 파티션 키를 지정해야 합니다. 등식 또는 IN 연산자를 사용합니다.  
예를 들어, `Orders` 테이블에 `OrderID` 파티션 키 및 키가 아닌 기타 속성(`Address` 등)이 있는 경우 다음 문을 사용하면 전체 테이블 스캔이 되지 않습니다.  

```
SELECT * 
FROM "Orders" 
WHERE OrderID = 100

SELECT * 
FROM "Orders" 
WHERE OrderID = 100 and Address='some address'

SELECT * 
FROM "Orders" 
WHERE OrderID = 100 or OrderID = 200

SELECT * 
FROM "Orders" 
WHERE OrderID IN [100, 300, 234]
```
그러나 다음 `SELECT` 문을 사용하면 전체 테이블 스캔이 됩니다.  

```
SELECT * 
FROM "Orders" 
WHERE OrderID > 1

SELECT * 
FROM "Orders" 
WHERE Address='some address'

SELECT * 
FROM "Orders" 
WHERE OrderID = 100 OR Address='some address'
```

***키***  
(선택 사항) 반환된 결과를 정렬하는 데 사용할 해시 키 또는 정렬 키입니다. 기본 순서는 오름차순(`ASC`)이며, 결과가 내림차순으로 반환되게 하려면 `DESC`를 지정합니다.

**참고**  
`WHERE` 절을 생략하면 테이블의 모든 항목이 검색됩니다.

## 예제
<a name="ql-reference.select.examples"></a>

다음 쿼리는 파티션 키 `OrderID`를 지정하고 등식 연산자를 사용하여 `Orders` 테이블에서 항목 하나(있는 경우)를 반환합니다.

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

다음 쿼리는 특정 파티션 키 `OrderID` 값을 OR 연산자로 지정하여 `Orders` 테이블에서 모든 항목을 반환합니다.

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

다음 쿼리는 특정 파티션 키 `OrderID` 값을 IN 연산자로 지정하여 `Orders` 테이블에서 모든 항목을 반환합니다. 반환되는 결과는 `OrderID` 키 속성 값을 기준으로 내림차순으로 표시됩니다.

```
SELECT OrderID, Total
FROM "Orders"
WHERE OrderID IN [1, 2, 3] ORDER BY OrderID DESC
```

다음 쿼리는 `Orders` 테이블에서 `Total`이 500보다 큰 모든 항목을 반환하는 전체 테이블 스캔을 표시합니다. 여기서 `Total`은 키가 아닌 속성입니다.

```
SELECT OrderID, Total 
FROM "Orders"
WHERE Total > 500
```

다음 쿼리는 IN 연산자와 키가 아닌 속성 `Total`을 사용하여 `Orders` 테이블에서 특정 `Total` 주문 범위 내의 모든 항목을 반환하는 전체 테이블 스캔을 표시합니다.

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

다음 쿼리는 BETWEEN 연산자가 키가 아닌 속성 `Total`을 사용하여 `Orders` 테이블에서 특정 `Total` 주문 범위 내의 모든 항목을 반환하는 전체 테이블 스캔을 표시합니다.

```
SELECT OrderID, Total 
FROM "Orders" 
WHERE Total BETWEEN 500 AND 600
```

다음 쿼리는 WHERE 절 조건에 파키션 키 `CustomerID` 및 정렬 키 `MovieID`를 지정하고 SELECT 절에 문서 경로를 사용하여 파이어스틱 디바이스를 사용해 시청한 첫 번째 날짜를 반환합니다.

```
SELECT Devices.FireStick.DateWatched[0] 
FROM WatchList 
WHERE CustomerID= 'C1' AND MovieID= 'M1'
```

다음 쿼리는 WHERE 절 조건에 문서 경로를 사용하여 2019년 12월 24일 이후 파이어스틱 디바이스가 처음 사용된 항목 목록을 반환하는 전체 테이블 스캔을 표시합니다.

```
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)
+ [파라미터](#ql-reference.update.parameters)
+ [반환 값](#ql-reference.update.return)
+ [예제](#ql-reference.update.examples)

## 구문
<a name="ql-reference.update.syntax"></a>

```
UPDATE  table  
[SET | REMOVE]  path  [=  data] […]
WHERE condition [RETURNING returnvalues]
<returnvalues>  ::= [ALL OLD | MODIFIED OLD | ALL NEW | MODIFIED NEW] *
```

## 파라미터
<a name="ql-reference.update.parameters"></a>

***테이블*\$1**  
(필수) 수정할 데이터가 포함된 테이블입니다.

***path***  
(필수) 생성하거나 수정할 속성 이름 또는 문서 경로입니다.

***data***  
(필수) 속성 값 또는 작업의 결과입니다.  
SET과 함께 사용할 수 있는 작업은 다음과 같습니다.  
+ LIST\$1APPEND: 목록 형식에 값을 추가합니다.
+ SET\$1ADD: 숫자 또는 문자열 집합에 값을 추가합니다.
+ SET\$1DELETE: 숫자 또는 문자열 집합에서 값을 제거합니다.

*** 조건***  
(필수) 수정할 항목의 선택 기준입니다. 이 조건은 단일 기본 키 값으로 확인되어야 합니다.

***returnvalues***  
(선택 사항) 항목 속성이 업데이트되기 전이나 후에 표시되는 해당 속성을 가져오려면 `returnvalues`를 사용합니다. 유효한 값은 다음과 같습니다.  
+ `ALL OLD *` - 업데이트 작업 전에 표시된 항목 속성을 모두 반환합니다.
+ `MODIFIED OLD *` - 업데이트 작업 전에 표시된 업데이트된 속성만 반환합니다.
+ `ALL NEW *` - 업데이트 작업 후에 표시되는 항목 속성을 모두 반환합니다.
+ `MODIFIED NEW *` - `UpdateItem` 작업 후에 표시되는 업데이트된 속성만 반환합니다.

## 반환 값
<a name="ql-reference.update.return"></a>

이 문은 `returnvalues` 파라미터를 지정하지 않는 경우 값을 반환하지 않습니다.

**참고**  
DynamoDB 테이블의 모든 항목에 대해 UPDATE 문의 WHERE 절이 true로 평가되지 않으면 `ConditionalCheckFailedException`이 반환됩니다.

## 예제
<a name="ql-reference.update.examples"></a>

기존 항목의 속성 값을 업데이트합니다. 속성이 없으면 새로 생성됩니다.

다음 쿼리는 숫자 형식의 속성(`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'
```

다음 쿼리는 `AwardDetail` 맵에 `"Music"`을 추가하여 `BillBoard` 테이블에서 항목을 업데이트합니다.

```
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'
```

다음 쿼리는 문자열 집합 `BandMembers`에 `newbandmember`를 추가하여 `"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)
+ [파라미터](#ql-reference.delete.parameters)
+ [반환 값](#ql-reference.delete.return)
+ [예제](#ql-reference.delete.examples)

## 구문
<a name="ql-reference.delete.syntax"></a>

```
DELETE FROM table 
 WHERE condition [RETURNING returnvalues]
 <returnvalues>  ::= ALL OLD *
```

## 파라미터
<a name="ql-reference.delete.parameters"></a>

***테이블*\$1**  
(필수) 삭제할 항목이 포함된 DynamoDB 테이블입니다.

*** 조건***  
(필수) 삭제할 항목의 선택 기준입니다. 이 조건은 단일 기본 키 값으로 확인되어야 합니다.

***returnvalues***  
(선택 사항) 항목 속성이 삭제되기 전에 표시된 해당 속성을 가져오려면 `returnvalues`를 사용합니다. 유효한 값은 다음과 같습니다.  
+ `ALL OLD *` - 이전 항목의 내용이 반환됩니다.

## 반환 값
<a name="ql-reference.delete.return"></a>

이 문은 `returnvalues` 파라미터를 지정하지 않는 경우 값을 반환하지 않습니다.

**참고**  
DELETE가 실행된 대상 항목과 기본 키가 같은 항목이 DynamoDB 테이블에 없는 경우 삭제된 항목이 0개인 SUCCESS가 반환됩니다. 테이블에 기본 키가 같은 항목이 있지만 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)
+ [파라미터](#ql-reference.insert.parameters)
+ [반환 값](#ql-reference.insert.return)
+ [예제](#ql-reference.insert.examples)

## 구문
<a name="ql-reference.insert.syntax"></a>

단일 항목을 삽입합니다.

```
INSERT INTO table VALUE item
```

## 파라미터
<a name="ql-reference.insert.parameters"></a>

***테이블*\$1**  
(필수) 데이터를 삽입할 테이블입니다. 이미 있는 테이블이어야 합니다.

***item***  
(필수) [PartiQL 튜플](https://partiql.org/docs.html)로 표시된 유효한 DynamoDB 항목입니다. 항목을 *하나*만 지정해야 하며 항목의 각 속성 이름은 대/소문자를 구분하고 PartiQL에서 *작은* 따옴표(`'...'`)로 표시될 수 있습니다.  
문자열 값도 PartiQL에서 *작은* 따옴표(`'...'`)로 표시될 수 있습니다.

## 반환 값
<a name="ql-reference.insert.return"></a>

이 문은 값을 반환하지 않습니다.

**참고**  
DynamoDB 테이블에 삽입되는 항목과 기본 키가 같은 항목이 이미 있는 경우 `DuplicateItemException`이 반환됩니다.

## 예제
<a name="ql-reference.insert.examples"></a>

```
INSERT INTO "Music" value {'Artist' : 'Acme Band','SongTitle' : 'PartiQL Rocks'}
```

# DynamoDB에서 PartiQL 함수 사용
<a name="ql-functions"></a>

Amazon DynamoDB의 PartiQL은 SQL 표준 함수의 다음과 같은 기본 제공 변형을 지원합니다.

**참고**  
이 목록에 없는 모든 SQL 함수는 현재 DynamoDB에서 지원되지 않습니다.

## 집계 함수
<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를 사용하면 [TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems) API에서 `ConditionCheck`가 하는 기능을 똑같이 수행할 수 있습니다. EXISTS 함수는 트랜잭션에서만 사용할 수 있습니다.

값이 지정된 경우 값이 비어 있지 않은 컬렉션이면 `TRUE`를 반환합니다. 그렇지 않은 경우 `FALSE`를 반환합니다.

**참고**  
이 함수는 트랜잭션 작업에서만 사용할 수 있습니다.

## 구문
<a name="ql-functions.exists.syntax"></a>

```
EXISTS ( statement )
```

## 인수
<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>

*경로*  
(필수) 사용할 속성 이름 또는 문서 경로입니다.

*USD 상당*  
(필수) 검색할 문자열입니다.

## 반환 타입
<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*  
(필수) 사용할 속성 이름입니다.

type**  
(필수) 확인할 속성 형식입니다. 유효한 값 목록은 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>

*경로*  
(필수) 사용할 속성 이름 또는 문서 경로입니다.

*substring*  
(필수) 확인할 속성 하위 문자열 또는 집합 멤버입니다. 자세한 내용은 DynamoDB [contains](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) 함수를 참조하세요.

## 반환 타입
<a name="ql-functions.contains.return-type"></a>

`bool`

## 예시
<a name="ql-functions.contains.examples"></a>

```
SELECT * FROM "Orders" WHERE "OrderID"=1 AND contains("Address", 'Kirkland')
```

# 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)를 지원합니다.

**참고**  
이 목록에 없는 모든 SQL 연산자는 현재 DynamoDB에서 지원되지 않습니다.

## 산술 연산자
<a name="ql-operators.arithmetic"></a>


****  

| 연산자 | 설명 | 
| --- | --- | 
| \$1 | 더하기 | 
| - | 차감 | 

## 비교 연산자
<a name="ql-operators.comparison"></a>


****  

| 연산자 | 설명 | 
| --- | --- | 
| = | 같음 | 
| <> | 같지 않음 | 
| \$1= | 같지 않음 | 
| > | 보다 큼 | 
| < | 보다 작음 | 
| >= | 크거나 같음 | 
| <= | 작거나 같음 | 

## 논리 연산자
<a name="ql-operators.logical"></a>


****  

| 연산자 | 설명 | 
| --- | --- | 
| 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 Transactions를 사용하여 복잡한 워크플로 관리](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transactions.html)를 참조하세요.

**참고**  
전체 트랜잭션은 읽기 또는 쓰기 문으로 구성해야 합니다. 하나의 트랜잭션에서 두 가지를 모두 혼용할 수는 없습니다. EXISTS 함수는 예외입니다. [TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems) API 작업의 `ConditionCheck`와 유사한 방식으로 특정 항목 속성의 조건을 확인하는 데 사용할 수 있습니다.

**Topics**
+ [구문](#ql-reference.multiplestatements.transactions.syntax)
+ [파라미터](#ql-reference.multiplestatements.transactions.parameters)
+ [반환 값](#ql-reference.multiplestatements.transactions.return)
+ [예제](#ql-reference.multiplestatements.transactions.examples)

## 구문
<a name="ql-reference.multiplestatements.transactions.syntax"></a>

```
[
   {
      "Statement":" statement ",
      "Parameters":[
         {
            " parametertype " : " parametervalue "
         }, ...]
   } , ...
]
```

## 파라미터
<a name="ql-reference.multiplestatements.transactions.parameters"></a>

*** 명령문***  
(필수) DynamoDB용 PartiQL에서 지원되는 문입니다.  
전체 트랜잭션은 읽기 또는 쓰기 문으로 구성해야 합니다. 하나의 트랜잭션에서 두 가지를 모두 혼용할 수는 없습니다.

***parametertype***  
(선택 사항) ParitPartiQL 문을 지정할 때 파라미터가 사용된 경우 DynamoDB 형식입니다.

***parametervalue***  
(선택 사항) PartiQL 문을 지정할 때 파라미터가 사용된 경우 파라미터 값입니다.

## 반환 값
<a name="ql-reference.multiplestatements.transactions.return"></a>

이 문은 쓰기 작업(INSERT, UPDATE 또는 DELETE)에 대한 값을 반환하지 않습니다. 그러나 WHERE 절에 지정된 조건에 따라 읽기 작업 (SELECT) 에 대해 서로 다른 값을 반환합니다.

**참고**  
Singleton INSERT, UPDATE 또는 DELETE 작업 중 하나에서 오류를 반환하는 경우 트랜잭션이 `TransactionCanceledException` 예외로 취소되고 취소 이유 코드에 개별 singleton 작업의 오류가 포함됩니다.

## 예제
<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)
+ [파라미터](#ql-reference.multiplestatements.batching.parameters)
+ [예제](#ql-reference.multiplestatements.batching.examples)

## 구문
<a name="ql-reference.multiplestatements.batching.syntax"></a>

```
[
  {
    "Statement": "SELECT pk FROM ProblemSet WHERE pk = 'p#9StkWHYTxm7x2AqSXcrfu7' AND sk = 'info'"
  },
  {
    "Statement": "SELECT pk FROM ProblemSet WHERE pk = 'p#isC2ChceGbxHgESc4szoTE' AND sk = 'info'"
  }
]
```

```
[
   {
      "Statement":" statement ",
      "Parameters":[
         {
            " parametertype " : " parametervalue "
         }, ...]
   } , ...
]
```

## 파라미터
<a name="ql-reference.multiplestatements.batching.parameters"></a>

*** 명령문***  
(필수) DynamoDB용 PartiQL에서 지원되는 문입니다.  
+ 전체 배치는 읽기 문이나 쓰기 문 중 하나로 구성해야 하며, 하나의 배치에서 두 문을 함께 사용할 수는 없습니다.
+ `BatchExecuteStatement` 및 `BatchWriteItem`으로 배치당 25개 이하의 문을 실행할 수 있습니다.

***parametertype***  
(선택 사항) ParitPartiQL 문을 지정할 때 파라미터가 사용된 경우 DynamoDB 형식입니다.

***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 문(Select/Insert/Update/Delete) 허용
<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 select 문 허용
<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 insert 문 허용
<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에서 select 문은 허용하고 전체 테이블 스캔 문은 거부
<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>

AWS SDK for Java Document API를 사용하여 테이블의 Amazon DynamoDB 항목에 대한 일반적인 생성, 읽기, 업데이트 및 삭제(CRUD) 작업을 수행할 수 있습니다.

**참고**  
또한 SDK for Java에서는 객체 지속성 모델을 제공하므로 DynamoDB 테이블로 클라이언트 측 클래스를 매핑할 수 있습니다. 이러한 접근 방식을 활용하면 작성해야 할 코드가 줄어듭니다. 자세한 내용은 [Java 1.x: DynamoDBMapper](DynamoDBMapper.md) 섹션을 참조하세요.

이 단원에는 몇 가지 Java 문서 API 항목 작업을 수행하기 위한 Java 예제와 몇 가지 완전한 작업 예제가 나와 있습니다.

**Topics**
+ [항목 추가](#PutDocumentAPIJava)
+ [항목 가져오기](#JavaDocumentAPIGetItem)
+ [일괄 쓰기 - 여러 항목 추가 및 삭제](#BatchWriteDocumentAPIJava)
+ [일괄 가져오기: 여러 항목 가져오기](#JavaDocumentAPIBatchGetItem)
+ [항목 업데이트](#JavaDocumentAPIItemUpdate)
+ [항목 삭제](#DeleteMidLevelJava)
+ [예: AWS SDK for Java 문서 API를 사용하는 CRUD 작업](JavaDocumentAPICRUDExample.md)
+ [예: AWS SDK for Java Document API를 사용하는 일괄 작업](batch-operation-document-api-java.md)
+ [예: AWS SDK for Java 문서 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 코드 예제는 선택적 파라미터를 사용하여 항목을 업로드하기 위한 조건을 지정합니다. 지정하는 조건을 충족하지 못하면 AWS SDK for Java가 `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>

DynamoDB 테이블에 속성으로 JSON 문서를 저장할 수 있습니다. 그러려면 `withJSON`의 `Item` 메서드를 사용합니다. 이 메서드가 JSON 문서를 구문 분석하고 각 요소를 기본 DynamoDB 데이터 형식에 매핑합니다.

특정 제품에 대한 주문을 이행할 수 있는 공급업체를 포함하여 다음 JSON 문서를 저장한다고 가정해 보십시오.

**Example**  

```
{
    "V01": {
        "Name": "Acme Books",
        "Offices": [ "Seattle" ]
    },
    "V02": {
        "Name": "New Publishers, Inc.",
        "Offices": ["London", "New York"
        ]
    },
    "V03": {
        "Name": "Better Buy Books",
        "Offices": [ "Tokyo", "Los Angeles", "Sydney"
        ]
    }
}
```

`withJSON` 메서드를 사용하여 이 항목을 `ProductCatalog` 테이블의 `Map`라는 `VendorInfo` 속성에 저장할 수 있습니다. 다음은 이 작업을 수행하는 방법을 보여 주는 Java 코드 예제입니다.

```
// Convert the document into a String.  Must escape all double-quotes.
String vendorDocument = "{"
    + "    \"V01\": {"
    + "        \"Name\": \"Acme Books\","
    + "        \"Offices\": [ \"Seattle\" ]"
    + "    },"
    + "    \"V02\": {"
    + "        \"Name\": \"New Publishers, Inc.\","
    + "        \"Offices\": [ \"London\", \"New York\"" + "]" + "},"
    + "    \"V03\": {"
    + "        \"Name\": \"Better Buy Books\","
    +          "\"Offices\": [ \"Tokyo\", \"Los Angeles\", \"Sydney\""
    + "            ]"
    + "        }"
    + "    }";

Item item = new Item()
    .withPrimaryKey("Id", 210)
    .withString("Title", "Book 210 Title")
    .withString("ISBN", "210-2102102102")
    .withNumber("Price", 30)
    .withJSON("VendorInfo", vendorDocument);

PutItemOutcome outcome = table.putItem(item);
```

## 항목 가져오기
<a name="JavaDocumentAPIGetItem"></a>

단일 항목을 검색하려면 `getItem` 객체의 `Table` 메서드를 사용합니다. 다음 단계를 따릅니다.

1. `DynamoDB` 클래스의 인스턴스를 만듭니다. 

1. `Table` 클래스의 인스턴스를 만들어 사용할 테이블을 표시합니다.

1. `getItem` 인스턴스의 `Table` 메서드를 호출합니다. 검색하려는 항목의 기본 키를 지정해야 합니다.

다음 Java 코드 예는 앞의 단계를 보여줍니다. 이 코드는 지정된 파티션 기본 키가 있는 항목을 가져옵니다.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

Item item = table.getItem("Id", 210);
```

### 옵션 파라미터 지정
<a name="GetItemJavaDocumentAPIOptions"></a>

필수 파라미터 외에도 `getItem` 메서드에 대해 선택적 파라미터를 지정할 수 있습니다. 예를 들어 다음 Java 코드 예제는 선택적 메서드를 사용하여 특정 속성 목록만 검색하고 강력하게 일관된 읽기를 지정합니다. 읽기 일관성에 대한 자세한 내용은 [DynamoDB 읽기 일관성](HowItWorks.ReadConsistency.md)를 참조하십시오.

`ProjectionExpression`을 사용하여 전체 항목이 아닌 특정 속성이나 요소만 검색할 수 있습니다. `ProjectionExpression`은 문서 경로를 사용하여 최상위 또는 중첩된 속성을 지정할 수 있습니다. 자세한 내용은 [DynamoDB에서 프로젝션 표현식 사용](Expressions.ProjectionExpressions.md) 섹션을 참조하세요.

`getItem` 메서드의 파라미터는 읽기 일관성을 지정할 수 없도록 합니다. 그러나 하위 수준 `GetItemSpec` 작업에 대한 모든 입력에 전체 액세스 권한을 제공하는 `GetItem`를 생성할 수 있습니다. 아래의 코드 예제에서는 `GetItemSpec`을 생성하고 그 사양을 `getItem` 메서드에 대한 입력으로 사용합니다.

**Example**  

```
GetItemSpec spec = new GetItemSpec()
    .withPrimaryKey("Id", 206)
    .withProjectionExpression("Id, Title, RelatedItems[0], Reviews.FiveStar")
    .withConsistentRead(true);

Item item = table.getItem(spec);

System.out.println(item.toJSONPretty());
```

 사람이 읽을 수 있는 형식으로 `Item`을 인쇄하려면 `toJSONPretty` 메서드를 사용하십시오. 이전 예제의 출력은 다음과 같습니다.

```
{
  "RelatedItems" : [ 341 ],
  "Reviews" : {
    "FiveStar" : [ "Excellent! Can't recommend it highly enough! Buy it!", "Do yourself a favor and buy this" ]
  },
  "Id" : 123,
  "Title" : "20-Bicycle 123"
}
```

### GetItem 및 JSON 문서
<a name="GetItemJavaDocumentAPI.JSON"></a>

[PutItem 및 JSON 문서](#PutItemJavaDocumentAPI.JSON) 단원에서는 JSON 문서를 `Map`라는 `VendorInfo` 속성에 저장했습니다. `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` 메서드를 사용하면 단 한 번의 호출로 하나 이상의 테이블에 다수의 항목을 업로드하거나 삭제할 수 있습니다. 다음은 AWS SDK for Java Document 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
```

사용 가능한 예제는 [예: AWS SDK for Java 문서 API를 사용하는 일괄 쓰기 작업](batch-operation-document-api-java.md#JavaDocumentAPIBatchWrite) 섹션을 참조하세요.

## 일괄 가져오기: 여러 항목 가져오기
<a name="JavaDocumentAPIBatchGetItem"></a>

`batchGetItem` 메서드를 사용하면 하나 이상의 테이블에서 여러 항목을 검색할 수 있습니다. 단일 항목을 검색하려면 `getItem` 메서드를 사용합니다.

다음 단계를 따릅니다.

1. `DynamoDB` 클래스의 인스턴스를 만듭니다. 

1. 테이블에서 검색할 기본 키 값 목록을 설명하는 `TableKeysAndAttributes` 클래스의 인스턴스를 만듭니다. 단일 일괄 가져오기 작업에서 여러 테이블로부터 읽으려면 테이블마다 `TableKeysAndAttributes` 인스턴스 하나를 만들어야 합니다.

1. 이전 단계에서 생성한 `batchGetItem` 객체를 제공하여 `TableKeysAndAttributes` 메서드를 호출합니다.

다음 Java 코드 예는 앞의 단계를 보여줍니다. 이 예제에서는 `Forum` 테이블에서 항목 2개, `Thread` 테이블에서 항목 3개를 검색합니다.

```
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` 테이블의 book 항목을 업데이트합니다. 새로운 작성자를 `Authors` 집합에 추가하고 기존 `ISBN` 속성을 삭제합니다. 또한 가격을 1만큼 내립니다.

`ExpressionAttributeValues` 맵이 `UpdateExpression`에 사용됩니다. 런타임에 자리 표시자 `:val1` 및 `:val2`가 `Authors` 및 `Price`의 실제 값으로 바뀝니다.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

Map<String, String> expressionAttributeNames = new HashMap<String, String>();
expressionAttributeNames.put("#A", "Authors");
expressionAttributeNames.put("#P", "Price");
expressionAttributeNames.put("#I", "ISBN");

Map<String, Object> expressionAttributeValues = new HashMap<String, Object>();
expressionAttributeValues.put(":val1",
    new HashSet<String>(Arrays.asList("Author YY","Author ZZ")));
expressionAttributeValues.put(":val2", 1);   //Price

UpdateItemOutcome outcome =  table.updateItem(
    "Id",          // key attribute name
    101,           // key attribute value
    "add #A :val1 set #P = #P - :val2 remove #I", // UpdateExpression
    expressionAttributeNames,
    expressionAttributeValues);
```

### 옵션 파라미터 지정
<a name="UpdateItemJavaDocumentAPIOptions"></a>

필수 파라미터 외에도 업데이트가 발생하기 위해 충족되어야 하는 조건 등 `updateItem` 메서드에 대한 선택적 파라미터도 지정할 수 있습니다. 지정하는 조건을 충족하지 못하면 AWS SDK for Java가 `ConditionalCheckFailedException`을 내보냅니다. 예를 들어 다음 Java 코드 예제는 book 항목 가격을 25로 조건부 업데이트합니다. 기존 가격이 20일 경우에만 가격이 업데이트 되도록 `ConditionExpression`을 지정합니다.

**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` 속성을 하나씩 늘리며 이를 보여 줍니다. `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` 속성이 false임) `ProductCatalog`의 book 항목을 삭제하도록 `InPublication`을 지정합니다.

**Example**  

```
Map<String,Object> expressionAttributeValues = new HashMap<String,Object>();
expressionAttributeValues.put(":val", false);

DeleteItemOutcome outcome = table.deleteItem("Id",103,
    "InPublication = :val",
    null, // ExpressionAttributeNames - not used in this example
    expressionAttributeValues);
```

# 예: AWS SDK for Java 문서 API를 사용하는 CRUD 작업
<a name="JavaDocumentAPICRUDExample"></a>

다음 코드 예제는 Amazon DynamoDB 항목에 대한 CRUD 작업을 보여줍니다. 이 예에서는 항목을 만들고, 검색하고, 다양한 업데이트를 수행하고, 마지막으로 항목을 삭제합니다.

**참고**  
또한 SDK for Java에서는 객체 지속성 모델을 제공하므로 DynamoDB 테이블로 클라이언트 측 클래스를 매핑할 수 있습니다. 이러한 접근 방식을 활용하면 작성해야 할 코드가 줄어듭니다. 자세한 내용은 [Java 1.x: DynamoDBMapper](DynamoDBMapper.md) 섹션을 참조하세요.

**참고**  
아래 코드 예제는 [DynamoDB에서 테이블 생성 및 코드 예시에 대한 데이터 로드](SampleData.md) 단원의 지침에 따라 이미 계정의 DynamoDB에 데이터를 로드하였다고 가정한 것입니다.  
다음 예제를 실행하기 위한 단계별 지침은 [Java 코드 예](CodeSamples.Java.md) 섹션을 참조하세요.

```
package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DeleteItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.UpdateItemOutcome;
import com.amazonaws.services.dynamodbv2.document.spec.DeleteItemSpec;
import com.amazonaws.services.dynamodbv2.document.spec.UpdateItemSpec;
import com.amazonaws.services.dynamodbv2.document.utils.NameMap;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;
import com.amazonaws.services.dynamodbv2.model.ReturnValue;

public class DocumentAPIItemCRUDExample {

    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    static String tableName = "ProductCatalog";

    public static void main(String[] args) throws IOException {

        createItems();

        retrieveItem();

        // Perform various updates.
        updateMultipleAttributes();
        updateAddNewAttribute();
        updateExistingAttributeConditionally();

        // Delete the item.
        deleteItem();

    }

    private static void createItems() {

        Table table = dynamoDB.getTable(tableName);
        try {

            Item item = new Item().withPrimaryKey("Id", 120).withString("Title", "Book 120 Title")
                    .withString("ISBN", "120-1111111111")
                    .withStringSet("Authors", new HashSet<String>(Arrays.asList("Author12", "Author22")))
                    .withNumber("Price", 20).withString("Dimensions", "8.5x11.0x.75").withNumber("PageCount", 500)
                    .withBoolean("InPublication", false).withString("ProductCategory", "Book");
            table.putItem(item);

            item = new Item().withPrimaryKey("Id", 121).withString("Title", "Book 121 Title")
                    .withString("ISBN", "121-1111111111")
                    .withStringSet("Authors", new HashSet<String>(Arrays.asList("Author21", "Author 22")))
                    .withNumber("Price", 20).withString("Dimensions", "8.5x11.0x.75").withNumber("PageCount", 500)
                    .withBoolean("InPublication", true).withString("ProductCategory", "Book");
            table.putItem(item);

        } catch (Exception e) {
            System.err.println("Create items failed.");
            System.err.println(e.getMessage());

        }
    }

    private static void retrieveItem() {
        Table table = dynamoDB.getTable(tableName);

        try {

            Item item = table.getItem("Id", 120, "Id, ISBN, Title, Authors", null);

            System.out.println("Printing item after retrieving it....");
            System.out.println(item.toJSONPretty());

        } catch (Exception e) {
            System.err.println("GetItem failed.");
            System.err.println(e.getMessage());
        }

    }

    private static void updateAddNewAttribute() {
        Table table = dynamoDB.getTable(tableName);

        try {

            UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", 121)
                    .withUpdateExpression("set #na = :val1").withNameMap(new NameMap().with("#na", "NewAttribute"))
                    .withValueMap(new ValueMap().withString(":val1", "Some value"))
                    .withReturnValues(ReturnValue.ALL_NEW);

            UpdateItemOutcome outcome = table.updateItem(updateItemSpec);

            // Check the response.
            System.out.println("Printing item after adding new attribute...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Failed to add new attribute in " + tableName);
            System.err.println(e.getMessage());
        }
    }

    private static void updateMultipleAttributes() {

        Table table = dynamoDB.getTable(tableName);

        try {

            UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", 120)
                    .withUpdateExpression("add #a :val1 set #na=:val2")
                    .withNameMap(new NameMap().with("#a", "Authors").with("#na", "NewAttribute"))
                    .withValueMap(
                            new ValueMap().withStringSet(":val1", "Author YY", "Author ZZ").withString(":val2",
                                    "someValue"))
                    .withReturnValues(ReturnValue.ALL_NEW);

            UpdateItemOutcome outcome = table.updateItem(updateItemSpec);

            // Check the response.
            System.out.println("Printing item after multiple attribute update...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Failed to update multiple attributes in " + tableName);
            System.err.println(e.getMessage());

        }
    }

    private static void updateExistingAttributeConditionally() {

        Table table = dynamoDB.getTable(tableName);

        try {

            // Specify the desired price (25.00) and also the condition (price =
            // 20.00)

            UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", 120)
                    .withReturnValues(ReturnValue.ALL_NEW).withUpdateExpression("set #p = :val1")
                    .withConditionExpression("#p = :val2").withNameMap(new NameMap().with("#p", "Price"))
                    .withValueMap(new ValueMap().withNumber(":val1", 25).withNumber(":val2", 20));

            UpdateItemOutcome outcome = table.updateItem(updateItemSpec);

            // Check the response.
            System.out.println("Printing item after conditional update to new attribute...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Error updating item in " + tableName);
            System.err.println(e.getMessage());
        }
    }

    private static void deleteItem() {

        Table table = dynamoDB.getTable(tableName);

        try {

            DeleteItemSpec deleteItemSpec = new DeleteItemSpec().withPrimaryKey("Id", 120)
                    .withConditionExpression("#ip = :val").withNameMap(new NameMap().with("#ip", "InPublication"))
                    .withValueMap(new ValueMap().withBoolean(":val", false)).withReturnValues(ReturnValue.ALL_OLD);

            DeleteItemOutcome outcome = table.deleteItem(deleteItemSpec);

            // Check the response.
            System.out.println("Printing item that was deleted...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Error deleting item in " + tableName);
            System.err.println(e.getMessage());
        }
    }
}
```

# 예: AWS SDK for Java Document API를 사용하는 일괄 작업
<a name="batch-operation-document-api-java"></a>

이 단원에서는 AWS SDK for Java 문서 API를 사용하여 Amazon DynamoDB에서 배치 쓰기 및 배치 가져오기를 수행하는 작업의 예를 제공합니다.

**참고**  
또한 SDK for Java에서는 객체 지속성 모델을 제공하므로 DynamoDB 테이블로 클라이언트 측 클래스를 매핑할 수 있습니다. 이러한 접근 방식을 활용하면 작성해야 할 코드가 줄어듭니다. 자세한 내용은 [Java 1.x: DynamoDBMapper](DynamoDBMapper.md) 섹션을 참조하세요.

**Topics**
+ [예: AWS SDK for Java 문서 API를 사용하는 일괄 쓰기 작업](#JavaDocumentAPIBatchWrite)
+ [예: AWS SDK for Java 문서 API를 사용하는 일괄 가져오기 작업](#JavaDocumentAPIBatchGet)

## 예: AWS SDK for Java 문서 API를 사용하는 일괄 쓰기 작업
<a name="JavaDocumentAPIBatchWrite"></a>

다음 Java 코드 예제에서는 `batchWriteItem` 메서드를 사용하여 다음의 일괄 및 삭제 작업을 수행합니다.
+ 한 항목을 `Forum` 테이블에 업로드합니다.
+ 한 항목을 `Thread` 테이블에서 업로드하고 삭제합니다.

일괄 쓰기 요청을 생성할 때는 하나 이상의 테이블에 대해 업로드 및 삭제 요청을 얼마든지 지정할 수 있습니다. 하지만 `batchWriteItem`은 단일 일괄 쓰기 작업에서 일괄 쓰기 요청의 크기와 업로드 및 삭제 작업의 수를 제한합니다. 이러한 제한을 초과할 경우에는 요청이 거부됩니다. 이러한 요청을 처리하는 데 충분한 처리량이 테이블에 할당되어 있지 않은 경우에는 응답 시 처리되지 않은 요청 항목이 반환됩니다.

다음은 응답을 확인하여 처리되지 않은 요청 항목의 유무를 점검하는 예제입니다. 미처리 요청 항목이 있는 경우에는 루프백이 발생하여 미처리 항목이 있는 `batchWriteItem` 요청을 다시 보냅니다. 이 가이드의 예제를 준수한 경우 이미 `Forum` 및 `Thread` 테이블이 생성되어 있습니다. 이러한 테이블은 프로그래밍 방식으로 생성하여 업로드할 수도 있습니다. 자세한 내용은 [AWS SDK for Java를 사용한 예시 테이블 생성 및 데이터 업로드](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);
        }

    }

}
```

## 예: AWS SDK for Java 문서 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());
        }

    }

}
```

# 예: AWS SDK for Java 문서 API를 사용하여 이진 형식 속성 처리
<a name="JavaDocumentAPIBinaryTypeExample"></a>

다음은 이진 형식 속성의 처리를 설명하는 Java 코드 예제입니다. 이 예제에서는 항목을 `Reply` 테이블에 추가합니다. 추가된 항목에는 압축 데이터가 저장된 이진수 형식의 속성(`ExtendedMessage`)이 포함되어 있습니다. 그런 다음 항목을 가져와서 모든 속성 값을 출력합니다. 이해를 돕기 위해 예제에서는 `GZIPOutputStream` 클래스를 사용해 샘플 스트림을 압축하여 `ExtendedMessage` 속성에 할당합니다. 이진 속성을 검색하면 `GZIPInputStream` 클래스를 사용하여 이 속성의 압축이 풀립니다.

**참고**  
또한 SDK for Java에서는 객체 지속성 모델을 제공하므로 DynamoDB 테이블로 클라이언트 측 클래스를 매핑할 수 있습니다. 이러한 접근 방식을 활용하면 작성해야 할 코드가 줄어듭니다. 자세한 내용은 [Java 1.x: DynamoDBMapper](DynamoDBMapper.md) 섹션을 참조하세요.

[DynamoDB에서 테이블 생성 및 코드 예시에 대한 데이터 로드](SampleData.md) 단원을 따랐다면 이미 `Reply` 테이블이 생성되어 있습니다. 이 테이블을 프로그래밍 방식으로 생성할 수도 있습니다. 자세한 내용은 [AWS SDK for Java를 사용한 예시 테이블 생성 및 데이터 업로드](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>

AWS SDK for .NET 하위 수준 API를 사용하여 테이블 항목에 대한 생성, 읽기, 업데이트, 삭제 작업(CRUD)을 수행할 수 있습니다. 다음은 .NET 하위 수준 API를 사용하여 데이터 CRUD를 작업할 때 따라야 할 공통 단계입니다.

1. `AmazonDynamoDBClient` 클래스(클라이언트)의 인스턴스를 만듭니다.

1. 각 요청 객체에서 작업에 따라 필요한 파라미터를 입력합니다.

   예를 들어 항목을 업로드할 때는 `PutItemRequest` 요청 객체를 사용하고, 기존 항목을 가져올 때는 `GetItemRequest` 요청 객체를 사용합니다.

   요청 객체를 사용하여 필수 파라미터와 옵션 파라미터를 모두 입력할 수도 있습니다.

1. 이전 단계에서 생성한 요청 객체를 전달하여 클라이언트 제공 메서드를 실행합니다.

   CRUD 작업을 위해 `AmazonDynamoDBClient` 클라이언트가 제공하는 메서드는 `PutItem`, `GetItem`, `UpdateItem` 및 `DeleteItem`입니다.

**Topics**
+ [항목 추가](#PutItemLowLevelAPIDotNet)
+ [항목 가져오기](#GetItemLowLevelDotNET)
+ [항목 업데이트](#UpdateItemLowLevelDotNet)
+ [원자성 카운터](#AtomicCounterLowLevelDotNet)
+ [항목 삭제](#DeleteMidLevelDotNet)
+ [일괄 쓰기 - 여러 항목 추가 및 삭제](#BatchWriteLowLevelDotNet)
+ [일괄 가져오기: 여러 항목 가져오기](#BatchGetLowLevelDotNet)
+ [예: AWS SDK for .NET 하위 수준 API를 사용하는 CRUD 작업](LowLevelDotNetItemsExample.md)
+ [예: AWS SDK for .NET 하위 수준 API를 사용하는 일괄 작업](batch-operation-lowlevel-dotnet.md)
+ [예: AWS SDK for .NET 하위 수준 API를 사용하여 이진 형식 속성 처리](LowLevelDotNetBinaryTypeExample.md)

## 항목 추가
<a name="PutItemLowLevelAPIDotNet"></a>

`PutItem` 메서드는 항목을 테이블에 업로드합니다. 항목이 존재하는 경우 전체 항목을 바꿉니다.

**참고**  
전체 항목을 변경하지 않고 특정 속성만 업데이트하는 경우에는 `UpdateItem` 메서드를 사용하면 됩니다. 자세한 내용은 [항목 업데이트](#UpdateItemLowLevelDotNet) 섹션을 참조하세요.

다음은 하위 수준 .NET SDK API를 사용하여 항목을 업로드하는 단계입니다.

1. `AmazonDynamoDBClient` 클래스의 인스턴스를 만듭니다. 

1. `PutItemRequest` 클래스 인스턴스를 생성하여 필요한 파라미터를 입력합니다.

   항목을 업로드하려면 테이블 이름과 항목을 입력해야 합니다.

1. 이전 단계에서 생성한 `PutItemRequest` 객체를 입력하여 `PutItem` 메서드를 실행합니다.

다음 C\$1 예제에서는 이전 단계를 설명합니다. 이 예제에서는 항목을 `ProductCatalog` 테이블에 업로드합니다.

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new PutItemRequest
{
   TableName = tableName,
   Item = new Dictionary<string, AttributeValue>()
      {
          { "Id", new AttributeValue { N = "201" }},
          { "Title", new AttributeValue { S = "Book 201 Title" }},
          { "ISBN", new AttributeValue { S = "11-11-11-11" }},
          { "Price", new AttributeValue { S = "20.00" }},
          {
            "Authors",
            new AttributeValue
            { SS = new List<string>{"Author1", "Author2"}   }
          }
      }
};
client.PutItem(request);
```

위 예제에서 업로드한 book 항목에는 `Id`, `Title`, `ISBN` 및 `Authors` 속성이 있습니다. `Id`는 숫자 형식의 속성이고, 나머지 모든 속성들은 문자열 형식입니다. 작성자는 `String` 집합입니다.

### 옵션 파라미터 지정
<a name="PutItemLowLevelAPIDotNetOptions"></a>

아래 C\$1 예제에서와 같이 `PutItemRequest` 객체를 사용하여 옵션 파라미터를 지정할 수도 있습니다. 이 예제에서 지정하는 옵션 파라미터는 다음과 같습니다.
+ `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) 섹션을 참조하세요.

다음은 하위 수준 AWS SDK for .NET API를 사용하여 기존 항목을 가져오는 단계입니다.

1. `AmazonDynamoDBClient` 클래스의 인스턴스를 만듭니다. 

1. `GetItemRequest` 클래스 인스턴스를 생성하여 필요한 파라미터를 입력합니다.

   항목을 가져오려면 테이블 이름과 항목의 기본 키를 입력해야 합니다.

1. 이전 단계에서 생성한 `GetItemRequest` 객체를 입력하여 `GetItem` 메서드를 실행합니다.

다음 C\$1 예제에서는 이전 단계를 설명합니다. 이 예제에서는 `ProductCatalog` 테이블에서 항목을 검색합니다.

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new GetItemRequest
 {
   TableName = tableName,
   Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "202" } } },
 };
 var response = client.GetItem(request);

// Check the response.
var result = response.GetItemResult;
var attributeMap = result.Item; // Attribute list in the response.
```

### 옵션 파라미터 지정
<a name="GetItemLowLevelDotNETOptions"></a>

아래 C\$1 예제에서와 같이 `GetItemRequest` 객체를 사용하여 옵션 파라미터를 지정할 수도 있습니다. 이 샘플에서 지정하는 옵션 파라미터는 다음과 같습니다.
+ `ProjectionExpression` 파라미터는 가져올 속성을 지정합니다.
+ `ConsistentRead` 파라미터는 Strongly Consistent Read를 실행합니다. 읽기 일관성에 대한 자세한 내용은 [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인 경우에는 입력한 속성이 있으면 삭제합니다.
  + `ADD`에서 `Action`를 사용하면 기존 집합(문자열 또는 숫자 집합)에 값을 추가하거나, 기존 숫자 속성 값에서 수치적으로 더하거나(양수 사용) 뺄 수 있습니다(음수 사용).

**참고**  
`PutItem` 작업은 업데이트도 가능합니다. 자세한 내용은 [항목 추가](#PutItemLowLevelAPIDotNet) 섹션을 참조하세요. 예를 들어 `PutItem`을 호출하여 항목을 업데이트할 때 기본 키가 있을 경우 `PutItem` 작업이 전체 항목을 변경합니다. 기존 항목에 속성이 있으나 그러한 속성이 입력에 지정되지 않은 경우, `PutItem` 작업은 그러한 속성을 삭제합니다. 그러나 `UpdateItem`은 지정된 입력 속성만 업데이트합니다. 해당 항목의 다른 모든 기존 속성은 변경되지 않고 그대로 유지됩니다.

다음은 하위 수준 .NET SDK API를 사용하여 기존 항목을 업데이트하는 단계입니다.

1. `AmazonDynamoDBClient` 클래스의 인스턴스를 만듭니다. 

1. `UpdateItemRequest` 클래스 인스턴스를 생성하여 필요한 파라미터를 입력합니다.

   이 인스턴스는 속성 추가, 기존 속성 업데이트 또는 속성 삭제 등과 같이 모든 업데이트를 설명하는 요청 객체입니다. 기존 속성을 삭제하려면 null 값으로 속성 이름을 지정합니다.

1. 이전 단계에서 생성한 `UpdateItemRequest` 객체를 입력하여 `UpdateItem` 메서드를 실행합니다.

다음 C\$1 코드 예제에서는 이전 단계를 설명합니다. 이 예제에서는 `ProductCatalog` 테이블의 book 항목을 업데이트합니다. 새로운 작성자를 `Authors` 컬렉션에 추가하고 기존 `ISBN` 속성을 삭제합니다. 또한 가격을 1만큼 내립니다.



```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new UpdateItemRequest
{
    TableName = tableName,
    Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "202" } } },
    ExpressionAttributeNames = new Dictionary<string,string>()
    {
        {"#A", "Authors"},
        {"#P", "Price"},
        {"#NA", "NewAttribute"},
        {"#I", "ISBN"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":auth",new AttributeValue { SS = {"Author YY","Author ZZ"}}},
        {":p",new AttributeValue {N = "1"}},
        {":newattr",new AttributeValue {S = "someValue"}},
    },

    // This expression does the following:
    // 1) Adds two new authors to the list
    // 2) Reduces the price
    // 3) Adds a new attribute to the item
    // 4) Removes the ISBN attribute from the item
    UpdateExpression = "ADD #A :auth SET #P = #P - :p, #NA = :newattr REMOVE #I"
};
var response = client.UpdateItem(request);
```

### 옵션 파라미터 지정
<a name="UpdateItemLowLevelDotNETOptions"></a>

아래 C\$1 예제에서와 같이 `UpdateItemRequest` 객체를 사용하여 옵션 파라미터를 지정할 수도 있습니다. 이 예제에서 지정하는 옵션 파라미터는 다음과 같습니다.
+ `ExpressionAttributeValues` 및 `ConditionExpression` 파라미터는 기존 가격이 20.00인 경우에만 가격을 업데이트하도록 지정합니다.
+ `ReturnValues` 파라미터는 응답 시 업데이트된 항목을 요청합니다.

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new UpdateItemRequest
{
    Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "202" } } },

    // Update price only if the current price is 20.00.
    ExpressionAttributeNames = new Dictionary<string,string>()
    {
        {"#P", "Price"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":newprice",new AttributeValue {N = "22"}},
        {":currprice",new AttributeValue {N = "20"}}
    },
    UpdateExpression = "SET #P = :newprice",
    ConditionExpression = "#P = :currprice",
    TableName = tableName,
    ReturnValues = "ALL_NEW" // Return all the attributes of the updated item.
};

var response = client.UpdateItem(request);
```

자세한 내용은 [UpdateItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html) 단원을 참조하세요.

## 원자성 카운터
<a name="AtomicCounterLowLevelDotNet"></a>

`updateItem`을 사용하여 원자성 카운터를 구현할 수 있습니다. 이는 다른 쓰기 요청과 충돌하지 않고도 기존 속성의 값을 증감합니다. 원자성 카운터를 업데이트하려면 `updateItem` 파라미터에서 `Number` 형식의 속성을 가진 `UpdateExpression`을 사용하고, `ADD`에서는 `Action`을 사용합니다.

다음 예제는 `Quantity` 속성을 하나씩 늘리며 이를 보여 줍니다.

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new UpdateItemRequest
{
    Key = new Dictionary<string, AttributeValue>() { { "Id", new AttributeValue { N = "121" } } },
    ExpressionAttributeNames = new Dictionary<string, string>()
    {
        {"#Q", "Quantity"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":incr",new AttributeValue {N = "1"}}
    },
    UpdateExpression = "SET #Q = #Q + :incr",
    TableName = tableName
};

var response = client.UpdateItem(request);
```

## 항목 삭제
<a name="DeleteMidLevelDotNet"></a>

`DeleteItem` 메서드는 테이블에서 항목을 삭제합니다.

다음은 하위 수준 .NET SDK API를 사용하여 항목을 삭제하는 단계입니다.

1. `AmazonDynamoDBClient` 클래스의 인스턴스를 만듭니다. 

1. `DeleteItemRequest` 클래스 인스턴스를 생성하여 필요한 파라미터를 입력합니다.

    항목을 삭제하려면 테이블 이름과 항목의 기본 키가 필요합니다.

1. 이전 단계에서 생성한 `DeleteItemRequest` 객체를 입력하여 `DeleteItem` 메서드를 실행합니다.

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new DeleteItemRequest
{
    TableName = tableName,
    Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "201" } } },
};

var response = client.DeleteItem(request);
```

### 옵션 파라미터 지정
<a name="DeleteItemLowLevelDotNETOptions"></a>

아래 C\$1 코드 예제에서와 같이 `DeleteItemRequest` 객체를 사용하여 옵션 파라미터를 지정할 수도 있습니다. 이 예제에서 지정하는 옵션 파라미터는 다음과 같습니다.
+ `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 SDK API를 사용하여 다수의 항목을 가져오는 단계입니다.

1. `AmazonDynamoDBClient` 클래스의 인스턴스를 만듭니다. 

1. `BatchWriteItemRequest` 클래스 인스턴스를 생성하여 모든 업로드 및 삭제 작업을 설명합니다.

1. 이전 단계에서 생성한 `BatchWriteItemRequest` 객체를 입력하여 `BatchWriteItem` 메서드를 실행합니다.

1. 응답을 처리합니다. 응답과 함께 반환되는 요청 항목 중 처리하지 않은 항목이 있는지 확인해야 합니다. 프로비저닝된 처리량이 할당량에 이르거나 일시적 오류가 발생하면 이러한 경우가 발생할 수 있습니다. 또한 DynamoDB는 요청 시 지정하는 요청 크기나 작업 수를 제한합니다. 따라서 이러한 제한을 초과할 경우 DynamoDB가 요청을 거부하기도 합니다. 자세한 내용은 [BatchWriteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html)을 참조하세요.

다음 C\$1 코드 예제에서는 이전 단계를 설명합니다. 아래 예제는 `BatchWriteItemRequest`를 생성하여 다음 쓰기 작업을 실행합니다.
+ `Forum` 테이블에 항목을 업로드합니다.
+ `Thread` 테이블에서 항목을 업로드하고 삭제합니다.

그런 다음 코드가 `BatchWriteItem`을 실행하여 배치 작업을 시작합니다.

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();

string table1Name = "Forum";
string table2Name = "Thread";

var request = new BatchWriteItemRequest
 {
   RequestItems = new Dictionary<string, List<WriteRequest>>
    {
      {
        table1Name, new List<WriteRequest>
        {
          new WriteRequest
          {
             PutRequest = new PutRequest
             {
                Item = new Dictionary<string,AttributeValue>
                {
                  { "Name", new AttributeValue { S = "Amazon S3 forum" } },
                  { "Threads", new AttributeValue { N = "0" }}
                }
             }
          }
        }
      } ,
      {
        table2Name, new List<WriteRequest>
        {
          new WriteRequest
          {
            PutRequest = new PutRequest
            {
               Item = new Dictionary<string,AttributeValue>
               {
                 { "ForumName", new AttributeValue { S = "Amazon S3 forum" } },
                 { "Subject", new AttributeValue { S = "My sample question" } },
                 { "Message", new AttributeValue { S = "Message Text." } },
                 { "KeywordTags", new AttributeValue { SS = new List<string> { "Amazon S3", "Bucket" }  } }
               }
            }
          },
          new WriteRequest
          {
             DeleteRequest = new DeleteRequest
             {
                Key = new Dictionary<string,AttributeValue>()
                {
                   { "ForumName", new AttributeValue { S = "Some forum name" } },
                   { "Subject", new AttributeValue { S = "Some subject" } }
                }
             }
          }
        }
      }
    }
 };
response = client.BatchWriteItem(request);
```

사용 가능한 예제는 [예: AWS SDK for .NET 하위 수준 API를 사용하는 일괄 작업](batch-operation-lowlevel-dotnet.md) 섹션을 참조하세요.

## 일괄 가져오기: 여러 항목 가져오기
<a name="BatchGetLowLevelDotNet"></a>

`BatchGetItem` 메서드를 사용하면 하나 이상의 테이블에서 여러 항목을 검색할 수 있습니다.

**참고**  
단일 항목을 검색하려면 `GetItem` 메서드를 사용합니다.

다음은 하위 수준 AWS SDK for .NET API를 사용하여 다수의 항목을 가져오는 단계입니다.

1. `AmazonDynamoDBClient` 클래스의 인스턴스를 만듭니다. 

1. `BatchGetItemRequest` 클래스 인스턴스를 생성하여 필요한 파라미터를 입력합니다.

   다수의 항목을 가져오려면 테이블 이름과 기본 키 값의 목록이 필요합니다.

1. 이전 단계에서 생성한 `BatchGetItemRequest` 객체를 입력하여 `BatchGetItem` 메서드를 실행합니다.

1. 응답을 처리합니다. 처리하지 않은 키가 있는지 확인해야 합니다. 프로비저닝된 처리량이 할당량에 이르거나 일시적 오류가 발생하면 이러한 경우가 발생할 수 있습니다.

다음 C\$1 코드 예제에서는 이전 단계를 설명합니다. 아래 예제에서는 `Forum` 및 `Thread` 테이블에서 항목을 가져옵니다. 요청에 따라 지정하는 항목 수는 `Forum` 테이블에서 2개, 그리고 `Thread` 테이블에서 3개입니다. 따라서 이 요청에는 두 테이블의 항목이 모두 포함됩니다. 코드를 보면 응답의 처리 방식을 알 수 있습니다.



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

아래 C\$1 코드 예제에서와 같이 `BatchGetItemRequest` 객체를 사용하여 옵션 파라미터를 지정할 수도 있습니다. 이 예제에서는 `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)을 참조하세요.

# 예: AWS SDK for .NET 하위 수준 API를 사용하는 CRUD 작업
<a name="LowLevelDotNetItemsExample"></a>

다음 C\$1 코드 예제는 Amazon DynamoDB 항목에 대한 CRUD 작업을 보여줍니다. 여기 예제에서는 항목을 `ProductCatalog` 테이블에 추가하고, 항목을 가져오고, 다수의 업데이트를 실행하고, 그리고 마지막으로 항목을 삭제합니다. 이 테이블을 만들지 않은 경우 프로그래밍 방식으로 만들 수도 있습니다. 자세한 내용은 [AWS SDK for .NET를 사용한 예시 테이블 생성 및 데이터 업로드](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("************************************************");
        }
    }
}
```

# 예: AWS SDK for .NET 하위 수준 API를 사용하는 일괄 작업
<a name="batch-operation-lowlevel-dotnet"></a>

**Topics**
+ [예: AWS SDK for .NET 하위 수준 API를 사용하는 일괄 쓰기 작업](#batch-write-low-level-dotnet)
+ [예: AWS SDK for .NET 하위 수준 API를 사용하는 일괄 가져오기 작업](#LowLevelDotNetBatchGet)

이번 단원에서는 *배치 쓰기*, *배치 가져오기* 같이 Amazon DynamoDB에서 지원되는 배치 작업의 예제를 제공합니다.

## 예: AWS SDK for .NET 하위 수준 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` 요청을 다시 보냅니다. 이러한 샘플 테이블은 프로그래밍 방식으로 생성하여 업로드할 수도 있습니다. 자세한 내용은 [AWS SDK for .NET를 사용한 예시 테이블 생성 및 데이터 업로드](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);
        }
    }
}
```

## 예: AWS SDK for .NET 하위 수준 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("************************************************");
        }
    }
}
```

# 예: AWS SDK for .NET 하위 수준 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();
            }
        }
    }
}
```