DynamoDB 테이블 구조1. 기본구조2. Key3. 처리량 과 파티션4. 사용 방법싱글테이블을 위한 키 디자인 Tenet1. Use case 정의2. 액세스 패턴을 식별3. 데이터 라이프 사이클 / Primary keys 식별3가지 공통점실습사전지식간단한 테이블 생성 과정 DynamoDB Client만날 수 있는 ERROR LIST
DynamoDB 테이블 구조
1. 기본구조
- 기본 구조는 테이블(Table) 단위이다.
- RDMBS에서 row라고 부르는
item
을 하나의 테이블에 무한히 저장한다.
- 하나의 아이탬은 여러개의
Attribute
를 가지는데, 이는 RDBMS의 column과 같은 역할을 한다.
- 하나의 아이탬은 최대 400kb를 가진다.
- dynamoDB는 하나의 아이탬(row)에서 한 글자만 변경되도 전체 아이탬(row)를 변경시키기 때문에 아이탬 크기는 최대한 작게 가져가면서, 여러 아이탬으로 개수를 많이 가져가는 것이 좋다.
⇒ Attributes 수를 줄이면서 데이터를 늘리는 것이 더 유리하다.
2. Key
- 각 테이블은 필수 요소인 파티션 키(
Partition Key
)를 가진다. RDBMS의 Primary Key와 같다. - PK는 Equal(
=
)로서 작용해야 한다.
- 각 테이블은 서브 요소인 정렬 키(
Sort Key
)를 가질 수 있다. - sort key는 1:N의 관계를 모델링 할 수 있고 오름차순 내림차순으로 정렬할 수 있다.
- sort key는 등호(
>,<
) 로서 작용해야 한다.
- 각 키를 통해 무엇으로 시작하는지 beginsWith / 무엇을 포함하는지 between 등의 조건으로 빠르게 검색할 수 있다.
- DynamoDB는 두 가지 Secondary Index를 제공한다.
- Global Secondary Index (GSI)
- 테이블의 PK 키 외에 다른 검색조건이 필요한 경우 언제든 추가 / 삭제가 자유롭다.
- 베이스 테이블의 Attributes 중 원하는 값을 지정하면 된다.
- Attributes 중 일부만 지정할 수도 있고, 전체를 지정할 수도 있다.
- GSI는 최대 25개까지 만들 수 있다.
- GSI의 Eventual Consistency가 각각 WCU와 RCU를 가지고 있어 사용비용 상승과 직결되 있기 때문에 유연한 사용이 필요하다.
- Local Secondary Index (LSI)
- 베이스 테이블에서 다른 sort key를 사용하고 싶을 때 생성할 수 있다.
- LSI는 테이블 생성시점에만 생성가능하고, 도중 삭제 불가능하기 때문에 쿼리의 유연성이 떨어져 일반적으로 사용이 권장되지 않는다.
- LSI는 생성 도중 최대 5개까지 생성 가능하다.
- Strong Consistency가 필요하다면 사용을 고려해 볼 수 있다.
- pk와 sort키 조합을 통해 원하는 아이탬을 최대한 빨리 찾아 return할 수 있는 것이 장점이다.
- key 디자인을 잘못 한다면 특정 파티션으로 데이터 쏠림이나 핫블럭이 유발될 수 있기 때문에 키 디자인을 잘 해야한다.
- DynamoDB에는 키가 될 값에 대하여 #을 사용하여 prefix나 sufix를 사용
- DynamoDB는 HTTP 통신을 합니다. 다른 Database가
TCP connection
기반인 것에 비해Connectionless
합니다.
- AWS Lambda와 DynamoDB가 아주 적합한
Severless
선택지이다.
- NoSQL의 탄생 목적이, 트래픽이 아주 많아져 연산의 속도를 극대화해야 하는 상황에서 탄생했기 때문에 scale in/out 능력이 아주 중요해졌다.
Partition Key
와Sort
키를 제외한 테이블의Attribute
들은 미리정의될 필요가 없다.
PK키와 Sort키를 제외한 키는 Schema가 미리 생성되어, 스키마대로 움직여야 하는 RDBMS와는 달리, 임의로 정의될 수 있다.
3. 처리량 과 파티션
파티션
- DynamoDB는 테이블 아래에는 물리적인 파티션 단위로 작업이 진행되고, 각 파티션 관리는 db(AWS)에서 알아서 관리하게되는 완전관리형 서버리스 DB 서비스다.
- 테이블이 새롭게 생성된다면 이전과 마찬가지로 여러 물리서버에 파티션단위로 분리되어 저장된다.
- 각 파티션은 초당 처리 최대용량이 존재하는데, 개별 파티션의 처리량은 변하지 않기 때문에 키 디자인을 통해 여러 파티션이 골고루 사용될 수 있도록 / 더 많은 파티션 단위로 분리될 수 있도록 키 설계를 하는 것이 매우 중요하다.
처리량
- 필요한 처리량이 있다면 테이블에 필요한 만큼만 설정할 수 있다.
- DynamoDB에서는 Write와 Read에 대한 처리량 단위로 Capacity Unit을 사용한다.
- 1WCU는 1초에 1kb 데이터를 write할 수 있다.
- 1RCU는 초당 4kb 데이터를 read할 수 있다.
- 각 테이블은 읽기 쓰기 처리량을 구분해서 정할 수 있어 초당 1만 RCU 혹은 3천 WCU 등으로 값을 지정해서 사용할 수 있고, 사용한 만큼만 과금된다.
4. 사용 방법
REST API 에서…
- GetItem
- pk의 정확한 값을 지정하고, 정확히 0개 또는 1개의 아이탬을 반환한다.
- QueryCommand
- pk의 정확한 값을 지정하고, 일치하는 아이탬(여러개 가능)을 반환한다.
- 선택적으로 non-key Attributes에 필터링 조건을 추가할 수 있다.
- key 조건과 일치하는 아이템의 크기에 따라 RCU를 소비하여 단일 결과를 반환한다.
- Scan
- 키를 지정하지 않는다. 키가 아닌 Attributes에 대한 필터 조건을 지정한다.
- 필터 표현식과 일치하는 테이블 모든 아이템을 반환한다.
- 테이블의 모든 아이탬을 읽기 위해 RCU를 소비, 주의깊게 사용을 생각해야 한다.
- 일반적으로 데이터를 검색할 때는 GetItem과 QueryCommand가 권장된다.
- 응답메세지가 1MB 가 넘어가는 경우 LastEvaluatedKey를 이용하여 페이징 처리 해야한다.
- 이 외에도 batch와 같은 기능을 통해, 최대 16MB 또는 100개의 아이탬을 한 번에 읽을 수 있다.
싱글테이블을 위한 키 디자인 Tenet

일반적으로 RDBMS처럼 관계를 짓지말고, 빠른 조회를 위해 테이블간 키 디자인을 잘 해야한다.
1. Use case 정의
- 첫 번째로 Use case가 DynamoDB와 잘 맞는지 고민해야 한다.
- 무한의 데이터 중에서 하나 혹은 원하는 데이터를 PK로 빠르게 찾는 것을 잘하는 서비스이다.
- 대량의 Range Scan, Full Text Search, Aggregation과 같은 것들은 잘 하지 못한다.
2. 액세스 패턴을 식별
- 데이터 모델링은 엔티티별로 생성하는 것이 아닌 하나의 테이블에서 시작하는 것이다.
- 하나하나의 테이블이 모두 리소스다. 운영환경이 200개가 있다고 가정하면, 200개의 테이블이 모두 관리 대상이 될 것이다.
- 각각의 테이블에 대해 WCU/RCU , 백업 복구 등을 해줘야 하는데 운영관리를 위해 완전관리인 DynamoDB를 사용하는 것인데 운영부담을 만들어서는 안된다.
- 테이블에 파티션 수가 많을 수록 Application에 데이터 액세스가 여러 개 파티션 동시에 일어날 확률이 높아 테이블 전체 성능이 올라가 핫 파티션 확률도 줄어들게 될 것이다.
- 그렇기 때문에 사이즈가 작은 여러 테이블 사용은 지양해야 한다.
- 반대로 사이즈가 큰 테이블을 지향해야 한다.
- Application의 종류는 OLTP여야 한다.
- OLAP인 분석이 필요한 경우는 외부로 분석 파이프라인을 만들어서 분석을 처리할 수 있게 만들어야 한다.
3. 데이터 라이프 사이클 / Primary keys 식별
- 데이터 라이프 사이클은 데이터 특성에 따라 TTL의 필요 여부를 고민해야 하고 백업 정책또한 반드시 고민해야 한다.
- DynamoDB는 PK키로만 데이터를 조회할 수 있기 때문에 중요하다.
- 싱글 테이블 디자인이 Application의 Entity를 하나의 테이블에서 Access할 수 있도록 만드는 것이다.
- 싱글 테이블은 일반적으론 다수의 테이블에 비해 운영 부담이 적거나 거의 없어지고, 높은 테이블 최대 쓰로틀링이 줄어들 수 있다는 장점이 있다.
- 하지만, 처음 NoSQL을 접하면 러닝커브가 높고 시계열 데이터나 엔티티 별로 다른 액세스 패턴을 가지는 경우는 적합하지 않다.
3가지 공통점
- 파티션 키를 UserID로 고정하고 시작
- 확장성 있는 규모 있는 서비스 구축을 위해 사용해야 하는데, userId로 파티션 키를 고정하면 한 사용자의 모든 데이터가 하나의 pk를 벗어날 수 없다는 점이 있다. 대량의 트래픽을 유발하는 헤비 유저를 염두해 두고 키 디자인을 할 필요가 있다.
- Entity별로 테이블을 만드려고 하는 것
- dynamoDB는 테이블 간 조인이 지원되지 않기 때문에 Application 별로 부담이 증가
- GSI를 액세스 패턴별로 만드려는 경향
- GSI는 하나하나가 비용과 직결되기 때문에, 사용을 최소화하는 것이 좋다.
실습
사전지식
DynamoDB를 먼저 사용하기 전에 알아야 하는 것이 있다.
- Data Structure
- Scalar Type : Number(숫자, N으로 표시), String(문자, S로 표시), Binary(B로 표시), Boolean and Null
- Document Types : 리스트와 맵
- Set Types : 숫자 집합(Number Set), 문자 집합(String Set), Binary Set(이진자료형 집합)
- Atribute : 하나의 아이템에 있는 하나의
element (요소)
를 의미한다. RDB에서의 column 한 개와 동일한 개념이다.attribute의 타입은string
,integer
,boolean
과 같은 심플한 타입과list
와maps
와 같은 복잡한 타입 모두 가능하다. - Number : N?
- String : S?
- 단순 기본 키의 경우 첫 번째 속성 값(파티션 키)의 최대 길이는 2048바이트입니다.
- 복합 기본 키의 경우 두 번째 속성 값(정렬 키)의 최대 길이는 1024바이트입니다.
2016-02-15
2015-12-21T17:42:34Z
20150311T122706Z
- Binary : B?
- 단순 기본 키의 경우 첫 번째 속성 값(파티션 키)의 최대 길이는 2048바이트다.
- 복합 기본 키의 경우 두 번째 속성 값(정렬 키)의 최대 길이는 1024바이트다.
- Boolean : BOOL?
- Null : NULL?
[]
배열 형식 : SS? OR NS?- Map : M?
DynamoDB의 Number타입은 쌩뚱맞게도, number로 지정하지만 서버에서 Put으로 넣을 때는 string으로 넣는다. 이에 대한 AWS 공식문서의 설명이 있다.
모든 숫자는 언어와 라이브러리 간의 호환성을 극대화하기 위해 네트워크를 통해 DynamoDB에 문자열로 전송됩니다. 하지만 DynamoDB는 해당 문자열을 연산 작업에서 숫자 형식 속성으로 처리합니다.
문자열은 UTF-8 이진수 인코딩을 사용하는 유니코드다. 속성이 인덱스 또는 테이블의 키로 사용되지 않고 최대 DynamoDB 항목 크기 제한인 400KB로 제한되는 경우 문자열의 최소 길이는 0일 수 있다.
DynamoDB에서는 문자열을 사용해 날짜 형식을 표시해야 한다. Date Type이 따로 존재하지 않기 때문이다. (ISO 8601 string으로 저장하는 것이 좋다.)
이진수 형식의 속성에는 압축 텍스트, 암호화 데이터 또는 이미지 같은 모든 이진수 데이터가 저장될 수 있다.
이진수 형식 속성으로 기본 키 속성을 정의하는 경우 다음 추가 제약이 적용된다.
데이터를 DynamoDB로 보내기 전에 Base64 인코딩 형식으로 이진수 값을 인코딩해야 한다.
사용 전 미리 바이너리 데이터 형태로 바꿔서 보내란 뜻이다.
true나 false상태를 저장할 수 있다.
Null은 알려지지 않았거나 정의되지 않은 상태의 속성을 나타낸다.
FavoriteThings: ["Cookies", "Coffee", 3.14159]
맵 형식 속성은 정렬되지 않은 이름-값 페어의 모음을 저장할 수 있다. 맵은 중괄호(
{ ... }
)로 묶는다.맵은 JSON 객체와 유사하다. 맵 요소에 저장할 수 있는 데이터 형식에는 제한이 없으며, 한 맵에 형식이 다른 요소도 함께 있을 수 있다.
맵은 DynamoDB에 JSON 문서를 저장하는 데 이상적이다. 다음은 문자열, 숫자 및 다른 맵을 포함하는 중첩 목록이 저장된 맵을 나타내는 예제이다.
{
Day: "Monday",
UnreadEmails: 42,
ItemsOnMyDesk: [
"Coffee Cup",
"Telephone",
{
Pens: { Quantity : 3},
Pencils: { Quantity : 2},
Erasers: { Quantity : 1}
}
]
}
- Return Value
기본적으로 DynamoDB의 return 값은 각 메서드의 Output이 된다.
export interface UpdateItemOutput {
Attributes?: Record<string, AttributeValue>;
ConsumedCapacity?: ConsumedCapacity;
ItemCollectionMetrics?: ItemCollectionMetrics;
}
예를들어,
UpdateItemOutput
은 위처럼 사용해야 하는데, 2번째를 제외하고 Attributes만 본다면const params = {
TableName: tableName,
Key: {
user_email: { S: email },
},
UpdateExpression: "SET #user_name= :user_name",
ExpressionAttributeNames: {
"#user_name": "user_name",
},
ExpressionAttributeValues: {
":user_name": {
S: name,
},
},
ReturnValues: "UPDATED_NEW",
};
위에
params
가 모두 Attributes가 된다. 놀랍게도, ReturnValues
를 제외한 다른 값들 중 하나라도빠진다면 바로 에러가 발생한다.
결국 UpdateItemOutput을 만족시키지 못한다면 Client 실행에 문제가 생길 수 있기 때문에 자료형을 받기 위해 생성한, Dto를 입력하기 보다는 각 커맨드의 Output을 return type으로 지정하는 것이 작성 시 더 효율적이라는 결론이 나왔다.
한편, 각 메서드마다 Output만 존재하는 것이 아니라, Input도 같이 존재하는데 Input과 Output이 같은 형태를 지니고 ( 같지 않더라도 매우 유사한) 있기 때문에 Output과 Input중 한 가지만 작성해도 된다는 결론이 나왔고 메서드의 Output만 작성하게 됐다.
// 이런식으로 Input의 타입도 잡아줄 수 있다.
const params : UpdateItemCommandInput = { };
위의 방식으로 Input타입을 잡는다면, 굳이 Output을 사용할 필요가 없기 때문에(형식이 이미 Input Type으로 정해짐)
제네릭에 return value를 정해서 사용할 수 있다.
public async isExistByHostEmail(
dynamoClient: DynamoDBClient,
tableName: string,
hostEmail: string
): Promise<Boolean> {
const params: GetItemInput = {
TableName: tableName,
Key: {
user_email: {
S: email,
},
},
};
const command = new GetItemCommand(params);
const result = await dynamoClient.send(command);
if (result.Item === undefined) return false;
else return true;
}
예를 든다면, 이런식이다.
Promise<Boolean>
으로 dyanmodb에 사용된 커맨드를 통해 나온 결론 혹은 value를 리턴하고 params에 itemInput으로 형식을 잡아주는 것이다.그렇기 때문에, 리턴될 값의 사용 유무에 따라 반환 타입을 지정해주면 된다.- 집합
DynamoDB에서도 숫자, 문자열 또는 이진수 값의 집합을 나타내는 형식을 지원한다. 집합 내의 모든 요소의 형식은 동일해야 한다. 예를 들어, 숫자 집합 형식의 속성은 숫자만 포함할 수 있으며, 문자열 집합은 문자열만 포함할 수 있는 식이다.
집합 내 값의 수에는 제한이 없다. 단, 값을 포함하는 항목이 DynamoDB 항목 크기 제한(400KB)을 초과하지 않아야 한다.
집합 내의 각 값은 고유해야 한다. 집합 내 값의 순서는 유지되지 않는다. 따라서 애플리케이션이 집합 내에서 요소가 특정 순서로 유지된다는 가정 하에 실행되지 않아야 한다. DynamoDB는 빈 집합을 지원하지 않지만 집합 내에서 빈 문자열과 이진 값이 허용된다.
["Black", "Green", "Red"]
[42.2, -19, 7.5, 3.14]
["U3Vubnk=", "UmFpbnk=", "U25vd3k="]
Item: {}
를 제외하고, 하나씩 설명하면Key
OrKeyConditionExpression
은
내가 사용하려는 테이블 혹은 보조 인덱스의 파티션키와 정렬키를 의미한다.
ConditionExpression
은
작업이 성공되기 위해서 표현되야하는 하나 이상의 조건을 의미한다.
GetItem, PutItem, UpdateItem, DeleteItem 등 다양한 DynamoDB 작업에 사용된다.
// ~와 일치하는지.
ConditionExpression: "user_name= :user_name",
ExpressionAttributeValues: {
":user_name": { S: name },
},
// ~보다 크다면.
"ConditionExpression": "attribute_not_exists(price) OR price >= :val",
"ExpressionAttributeValues": {
":val": {"N": "10"}
}
ExpressionAttributeNames
은
작업에 사용하려는 Key값에 alias를 붙여서 대신 사용하려는 목적으로 사용하는데, 보통은 Key값 그대로 받아서 사용한다.
ExpressionAttributeValues
은
실제로 대체될 Value가 들어갈 자리다. ExpressionAttributeNames 에서 alias 혹은 key를 그대로 받았다면, 그 값을 입력하거나 혹은 ExpressionAttributeNames 없이 ExpressionAttributeValues 만을 사용해서 검색할 수도 있다.
KeyConditionExpression:
"user_name = :user_name and user_created_at= :user_created_at",
ExpressionAttributeValues: {
":user_name": { S: name },
":user_created_at": { S: createdAt },
},
간단한 테이블 생성 과정

생성 버튼을 누르면 가장 먼저 위처럼 나온다.
파티션 키(PK)와 정렬 키가 (SORT) 있다. 일반적으로 정렬키는 초기 사용자에게 잘 설계해서 사용하는 것이 아니라면 추천하지 않는다.
그 이유는 일단 기본적으로 데이터 탐색 시 정렬키가 있다면 꼭 정렬 키를 받도록 반드시 keyCondition에 포함시켜야 하기 때문에 조회할 때 에로사항이 존재했고, 유저 Email을 통한 탐색으로 회원 테이블을 구성한 자사 서비스와는 어울리지 않았다는 경험에서 비롯된 이유이다.
차라리 LSI(로컬 보조 인덱스) 혹은 GSI(글로벌 보조 인덱스)를 활용해 DB를 조회하는 것이 더 효율적이었다.

그 다음 아래로 내려보면,
테이블 설정이 있는데 기본 설정을 선택하면 Dynamo DB가 프로비져닝(사용 안해도 리소스를 일부 할당) 되기 때문에 요금이 부과되기 때문에 사용한 만큼 요금이 청구되는 온디맨드가 초반 선택에서는 무난하다.

이제 온디맨드까지 골랐다면 LSI를 만들 수 있는데 주의 할 점은 LSI는 테이블 생성시에만 만들 수 있기 때문에 테이블을 확정짓기 전 끝까지 고민하는게 좋다.
간단한 테스트 환경 구성에서는 GSI를 사용하여, 자유롭게 구성하여도 좋겠지만 결국 Production Level까지 끌어올려야 한다면 테이블 설계를 신중하게 하여 초기 테이블의 LSI를 잘 설정하는 것이 중요하다.
태그를 달고 각 Key Value까지 모두 설정이 완료 됐다면, 해당 DB에 접근할 수 있는 권한을
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AccessTableAllIndexesOnBooks",
"Effect": "Allow",
"Action": [
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:DeleteItem",
"dynamodb:BatchWriteItem",
"dynamodb:GetItem",
"dynamodb:BatchGetItem",
"dynamodb:Scan",
"dynamodb:Query",
"dynamodb:ConditionCheckItem"
],
"Resource": [
"arn:aws:dynamodb:ap-northeast-2:account-ID:table/table_name",
"arn:aws:dynamodb:ap-northeast-2:account-ID:table/talbe_name/index/*" // table의 인덱스에 접근
]
}
]
}
이렇게 설정해준다면 이제 Dynamo DB에 접근하여 사용할 수 있다.
Typescirt에서 DynamoDB를 사용하는 방법은 크게
- aws-sdk v2에서 사용한
new Dyanmo()
로 생성자를 만들어 사용하는 방법
- aws-sdk v3에서 사용되는 Client를 만들어 사용하는 방법
이렇게 2가지가 존재하고, 내가 설명할 Dynamo DB를 사용하여 CRUD하는 방법은 Dynamo Client를 사용한 방식이다.
DynamoDB Client
- PutItemCommand. (Create)
PutCommand는 DynamoDB Client가 데이터를 DyanmoDB에 생성할 때 사용되는 메서드다.
PutCommand
const params: PutItemInput = {
TableName: tableName,
Item: marshall(
{
object Property...
},
{ convertClassInstanceToMap: true }
),
};
const command = new PutItemCommand(params);
return await dynamoClient.send(command);
나는 marshall을 사용했지만, 다른 방식을 알고 있다면 다른 방식을 사용해도 좋다.
마샬을 사용할 경우, convertClassInstanceToMap도 true가 아니라면 메서드가 실행되지 않는다. convertClassInstanceToMap가 true여야 JSON형태의 자료형을 DynamoDB의 자료형으로 매핑시켜주고, DB에 데이터가 삽입된다.
PK나 정렬키, 혹은 보조 인덱스에 사용되는 Key 타입은 미리 정해놓고 사용하는 것이기 때문에 저런 키값들로 사용되는 값들은 null로 사용될 수 없다.
또한, nulluable한 값들을 자유롭게 사용하는 것은 권장되지 않는다.
- QueryCommand. (Get)
QueryCommand는 DynamoDB Client가 테이블에서 데이터를 불러올 때 사용되는 메서드다.
QueryCommand
const params = {
TableName: tableName,
IndexName: "GSI Index Name",
KeyConditionExpression:
"user_name = :name and user_id = :id",
ExpressionAttributeValues: {
":name": { S: name },
":id": { N: id },
},
};
const command = new QueryCommand(params);
const result = await dynamoClient.send(command);
LSI나 GSI(글로벌 보조 인덱스)를 사용할 때는 꼭 내가 사용할 TableName과 IndexName이 필요하다.
- UpdateItemCommand. (Update)
UpdateItemCommand는 DynamoDB Client가 데이터를 수정할 때 사용되는 메서드다.
UpdateItemCommand
const params = {
TableName: tableName,
Key: {
user_email: { S: email },
},
UpdateExpression:
"SET #user_name = :user_name",
ExpressionAttributeNames: {
"#user_name": "user_name"
},
ExpressionAttributeValues: {
":user_name": {
S: name,
}
},
ReturnValues: "UPDATED_NEW",
};
const command = new UpdateItemCommand(params);
return await dynamoClient.send(command);
여러개의 값을 업데이트 할 때는,
SET #ID_1 = :ID_1, #ID_2 = :ID_2
형태로 사용한다.Querycommand를 사용할 때는 KeyCondition… 이었던 것에 비해 Update에서는
UpdateExpression라는 표현을 사용한다.
UPDATE문을 잘못 사용한다면, DB를 덮어씌우는 개념이기 때문에, 기존의 값 말고 이상한 값이 추가로 생성될 수 있다. 구문을 정확히 이해하고 사용하길 권장한다.
- DeleteItemCommand. (delete)
Delete문은 Update문과 기본적으로 구조가 비슷하다.
DeleteItemCommand
const params = {
TableName: tableName,
Key: {
user_email: { S: email },
},
ConditionExpression: "user_name = :user_name",
ExpressionAttributeValues: {
":user_name": { N: name },
},
};
const command = new DeleteItemCommand(params);
return await dynamoClient.send(command);
- TransactionCommand ( All )
Transaction 사용법은 일반 메서드와 다르다.
TrasactionCommand
public async transactUserData(
dynamoClient : DynamoDBClient, email:string): Promise<number> {
const params : TransactWriteCommandInput = {
TransactItems : [
{
/** has_invite to true */
Update : {
TableName : this.tableName,
Key : {
user_email: { S : email}
},
UpdateExpression : "SET #is_accces= :is_accces",
ExpressionAttributeNames : {
"#is_accces" : "is_accces"
},
ExpressionAttributeValues : {
":is_accces" : { BOOL : true }
}
}
},
{
/** has message true */
Put: {
TableName: this.tableName,
Item: {
user_email: { S: "my-item-id" },
user_name: { S: "My Item" }
....
},
},
}
]
}
const command = new TransactWriteItemsCommand(params);
const send = await dynamoClient.send(command);
return send.$metadata.httpStatusCode;
}
DyanmoClient의 Transaction Command를 통해 트랜잭션을 진행하게 되는데,
RDBMS처럼 connection을 따로 받아서 한다기 보다는 메서드 자체가 트랜잭션으로 돌아간다. 여기서 주의할 점은, 굳이 하나의 트랜잭션에 같은 메서드를 여러번 사용할 수 없다는 것이다.
일반적으로 하나의 테이블에 여러 테이블로 사용될 데이터를 넣어 놓는 것이 권장되지 않기 때문에 하나의 transaction에 같은 메서드를 중복하여 사용할 수 없다.
하나의 트랜잭션에 같은 메서드의 작업을 2번 하려고 하면,
ValidationException: Transaction request cannot include multiple operations on one item ( 트랜잭션 요청에 하나의 항목에 대한 여러 작업을 포함할 수 없습니다. )
라는 에러가 발생하게 된다.
만날 수 있는 ERROR LIST
- DynamoDB : Attribute name is a reserved keyword
DynamoDB TABLE 의 컬럼명과 DynamoDB 의 예약어가 충돌이 나서 발생하는 ERROR
내 케이스의 경우 user라는 예약어를 사용해서 에러가 발생했다.
예약어 목록
ABORT
ABSOLUTE
ACTION
ADD
AFTER
AGENT
AGGREGATE
ALL
ALLOCATE
ALTER
ANALYZE
AND
ANY
ARCHIVE
ARE
ARRAY
AS
ASC
ASCII
ASENSITIVE
ASSERTION
ASYMMETRIC
AT
ATOMIC
ATTACH
ATTRIBUTE
AUTH
AUTHORIZATION
AUTHORIZE
AUTO
AVG
BACK
BACKUP
BASE
BATCH
BEFORE
BEGIN
BETWEEN
BIGINT
BINARY
BIT
BLOB
BLOCK
BOOLEAN
BOTH
BREADTH
BUCKET
BULK
BY
BYTE
CALL
CALLED
CALLING
CAPACITY
CASCADE
CASCADED
CASE
CAST
CATALOG
CHAR
CHARACTER
CHECK
CLASS
CLOB
CLOSE
CLUSTER
CLUSTERED
CLUSTERING
CLUSTERS
COALESCE
COLLATE
COLLATION
COLLECTION
COLUMN
COLUMNS
COMBINE
COMMENT
COMMIT
COMPACT
COMPILE
COMPRESS
CONDITION
CONFLICT
CONNECT
CONNECTION
CONSISTENCY
CONSISTENT
CONSTRAINT
CONSTRAINTS
CONSTRUCTOR
CONSUMED
CONTINUE
CONVERT
COPY
CORRESPONDING
COUNT
COUNTER
CREATE
CROSS
CUBE
CURRENT
CURSOR
CYCLE
DATA
DATABASE
DATE
DATETIME
DAY
DEALLOCATE
DEC
DECIMAL
DECLARE
DEFAULT
DEFERRABLE
DEFERRED
DEFINE
DEFINED
DEFINITION
DELETE
DELIMITED
DEPTH
DEREF
DESC
DESCRIBE
DESCRIPTOR
DETACH
DETERMINISTIC
DIAGNOSTICS
DIRECTORIES
DISABLE
DISCONNECT
DISTINCT
DISTRIBUTE
DO
DOMAIN
DOUBLE
DROP
DUMP
DURATION
DYNAMIC
EACH
ELEMENT
ELSE
ELSEIF
EMPTY
ENABLE
END
EQUAL
EQUALS
ERROR
ESCAPE
ESCAPED
EVAL
EVALUATE
EXCEEDED
EXCEPT
EXCEPTION
EXCEPTIONS
EXCLUSIVE
EXEC
EXECUTE
EXISTS
EXIT
EXPLAIN
EXPLODE
EXPORT
EXPRESSION
EXTENDED
EXTERNAL
EXTRACT
FAIL
FALSE
FAMILY
FETCH
FIELDS
FILE
FILTER
FILTERING
FINAL
FINISH
FIRST
FIXED
FLATTERN
FLOAT
FOR
FORCE
FOREIGN
FORMAT
FORWARD
FOUND
FREE
FROM
FULL
FUNCTION
FUNCTIONS
GENERAL
GENERATE
GET
GLOB
GLOBAL
GO
GOTO
GRANT
GREATER
GROUP
GROUPING
HANDLER
HASH
HAVE
HAVING
HEAP
HIDDEN
HOLD
HOUR
IDENTIFIED
IDENTITY
IF
IGNORE
IMMEDIATE
IMPORT
IN
INCLUDING
INCLUSIVE
INCREMENT
INCREMENTAL
INDEX
INDEXED
INDEXES
INDICATOR
INFINITE
INITIALLY
INLINE
INNER
INNTER
INOUT
INPUT
INSENSITIVE
INSERT
INSTEAD
INT
INTEGER
INTERSECT
INTERVAL
INTO
INVALIDATE
IS
ISOLATION
ITEM
ITEMS
ITERATE
JOIN
KEY
KEYS
LAG
LANGUAGE
LARGE
LAST
LATERAL
LEAD
LEADING
LEAVE
LEFT
LENGTH
LESS
LEVEL
LIKE
LIMIT
LIMITED
LINES
LIST
LOAD
LOCAL
LOCALTIME
LOCALTIMESTAMP
LOCATION
LOCATOR
LOCK
LOCKS
LOG
LOGED
LONG
LOOP
LOWER
MAP
MATCH
MATERIALIZED
MAX
MAXLEN
MEMBER
MERGE
METHOD
METRICS
MIN
MINUS
MINUTE
MISSING
MOD
MODE
MODIFIES
MODIFY
MODULE
MONTH
MULTI
MULTISET
NAME
NAMES
NATIONAL
NATURAL
NCHAR
NCLOB
NEW
NEXT
NO
NONE
NOT
NULL
NULLIF
NUMBER
NUMERIC
OBJECT
OF
OFFLINE
OFFSET
OLD
ON
ONLINE
ONLY
OPAQUE
OPEN
OPERATOR
OPTION
OR
ORDER
ORDINALITY
OTHER
OTHERS
OUT
OUTER
OUTPUT
OVER
OVERLAPS
OVERRIDE
OWNER
PAD
PARALLEL
PARAMETER
PARAMETERS
PARTIAL
PARTITION
PARTITIONED
PARTITIONS
PATH
PERCENT
PERCENTILE
PERMISSION
PERMISSIONS
PIPE
PIPELINED
PLAN
POOL
POSITION
PRECISION
PREPARE
PRESERVE
PRIMARY
PRIOR
PRIVATE
PRIVILEGES
PROCEDURE
PROCESSED
PROJECT
PROJECTION
PROPERTY
PROVISIONING
PUBLIC
PUT
QUERY
QUIT
QUORUM
RAISE
RANDOM
RANGE
RANK
RAW
READ
READS
REAL
REBUILD
RECORD
RECURSIVE
REDUCE
REF
REFERENCE
REFERENCES
REFERENCING
REGEXP
REGION
REINDEX
RELATIVE
RELEASE
REMAINDER
RENAME
REPEAT
REPLACE
REQUEST
RESET
RESIGNAL
RESOURCE
RESPONSE
RESTORE
RESTRICT
RESULT
RETURN
RETURNING
RETURNS
REVERSE
REVOKE
RIGHT
ROLE
ROLES
ROLLBACK
ROLLUP
ROUTINE
ROW
ROWS
RULE
RULES
SAMPLE
SATISFIES
SAVE
SAVEPOINT
SCAN
SCHEMA
SCOPE
SCROLL
SEARCH
SECOND
SECTION
SEGMENT
SEGMENTS
SELECT
SELF
SEMI
SENSITIVE
SEPARATE
SEQUENCE
SERIALIZABLE
SESSION
SET
SETS
SHARD
SHARE
SHARED
SHORT
SHOW
SIGNAL
SIMILAR
SIZE
SKEWED
SMALLINT
SNAPSHOT
SOME
SOURCE
SPACE
SPACES
SPARSE
SPECIFIC
SPECIFICTYPE
SPLIT
SQL
SQLCODE
SQLERROR
SQLEXCEPTION
SQLSTATE
SQLWARNING
START
STATE
STATIC
STATUS
STORAGE
STORE
STORED
STREAM
STRING
STRUCT
STYLE
SUB
SUBMULTISET
SUBPARTITION
SUBSTRING
SUBTYPE
SUM
SUPER
SYMMETRIC
SYNONYM
SYSTEM
TABLE
TABLESAMPLE
TEMP
TEMPORARY
TERMINATED
TEXT
THAN
THEN
THROUGHPUT
TIME
TIMESTAMP
TIMEZONE
TINYINT
TO
TOKEN
TOTAL
TOUCH
TRAILING
TRANSACTION
TRANSFORM
TRANSLATE
TRANSLATION
TREAT
TRIGGER
TRIM
TRUE
TRUNCATE
TTL
TUPLE
TYPE
UNDER
UNDO
UNION
UNIQUE
UNIT
UNKNOWN
UNLOGGED
UNNEST
UNPROCESSED
UNSIGNED
UNTIL
UPDATE
UPPER
URL
USAGE
USE
USER
USERS
USING
UUID
VACUUM
VALUE
VALUED
VALUES
VARCHAR
VARIABLE
VARIANCE
VARINT
VARYING
VIEW
VIEWS
VIRTUAL
VOID
WAIT
WHEN
WHENEVER
WHERE
WHILE
WINDOW
WITH
WITHIN
WITHOUT
WORK
WRAPPED
WRITE
YEAR
ZONE
- ValidationException: Invalid UpdateExpression: An expression attribute name used in the document path is not defined; attribute name: #put_user
사용하고 있는 변수가 정의되어 있지 않거나 undefined인 경우 발생한다.
해결하기 위해선, 코드를 수정하거나 undefined인 데이터를 구분하여 존재하지 않는 항목을 생성해 DynamoDB에 저장해야 한다.
- Key element does not match the schema
기본키의 절반만 Key값만을 포함하고 있기에 생긴 에러이다. 메인키가와 정렬키가 모두 들어가야 한다.
Key : {
"id" : id,
},
// 정렬키가 빠져있기 때문에 에러가 발생했다.
Key : {
"id" : id,
"createdAt" : createdAt
},
// 기본키와 정렬키 모두 들어가 에러가 해제됐다.
Share article