Node.js의 DynamoDB BatchWriteItem (AWS SDK v3)

BatchWriteItem은 한 번의 요청으로 최대 25개 항목을 넣거나 삭제합니다. 이것은 작은 UpdateItem이 아닙니다. 모든 PutRequest는 저장된 항목 전체를 대체하며, v3 타입에는 조건을 붙일 자리가 아예 없습니다. DynamoDB의 배치 작업에서 한도와 부분 실패 모델을 다루고, 이 페이지는 v3 호출 자체와 그것이 조용히 데이터를 잃는 한 가지 경로를 다룹니다.

코드

import {BatchWriteItemCommand, DynamoDBClient} from '@aws-sdk/client-dynamodb';

const client = new DynamoDBClient({region: 'us-east-1'});

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

let requestItems = {
  Music: [
    {
      PutRequest: {
        Item: {
          Artist: {S: 'Arturo Sandoval'},
          SongTitle: {S: 'Cubano Chant'},
          AlbumTitle: {S: 'Danzon'},
          Year: {N: '1994'}
        }
      }
    },
    {
      PutRequest: {
        Item: {
          Artist: {S: 'Arturo Sandoval'},
          SongTitle: {S: 'A Mis Abuelos'},
          AlbumTitle: {S: 'Danzon'},
          Year: {N: '1994'}
        }
      }
    },
    {
      DeleteRequest: {
        Key: {Artist: {S: 'Ella Fitzgerald'}, SongTitle: {S: 'Misty'}}
      }
    }
  ]
};

let attempt = 0;

do {
  const response = await client.send(new BatchWriteItemCommand({RequestItems: requestItems}));

  // Writes that were throttled come back in UnprocessedItems — resubmit them
  // with exponential backoff until the map is empty.
  requestItems = response.UnprocessedItems;
  if (requestItems && Object.keys(requestItems).length > 0) {
    attempt += 1;
    await sleep(Math.min(100 * 2 ** attempt, 5000));
  }
} while (requestItems && Object.keys(requestItems).length > 0);

console.log('Batch written');

설명

  • 남은 항목이 담기는 멤버는 UnprocessedKeys가 아니라 UnprocessedItems입니다. 읽기 쪽은 다른 이름을 쓰는데, JavaScript에서는 여기서 오타를 내도 컴파일이 되고 undefined로 읽히면서 do/while이 한 번만 도는 호출로 바뀌어 스로틀링된 쓰기를 그대로 버립니다. TypeScript는 이를 잡아내지만 순수 JS는 잡지 못합니다.
  • 조건을 넣을 자리가 없습니다. v3의 WriteRequest 타입에는 선택적 멤버가 정확히 두 개, PutRequestDeleteRequest뿐이고 어느 쪽도 ConditionExpression이나 ReturnValues를 받지 않습니다. SDK가 보수적으로 군 것이 아닙니다. API 레퍼런스가 개별 put 및 delete 요청에는 조건을 지정할 수 없다고 못 박고 있습니다. 쓰기에 가드가 필요하다면 그것은 배치가 아니라 조건이 붙은 UpdateItem이나 트랜잭션의 몫입니다.
  • catch로 잡을 수 있는 두 가지 실수가 있고 둘 다 재시도 불가이며, err.name으로 구분합니다. 항목이 26개면 ValidationException / Too many items requested for the BatchWriteItem call이 발생합니다. 같은 키를 두 번 건드리면 Provided list of item keys contains duplicates가 발생하는데, 이 메시지는 put 두 개뿐 아니라 put+delete 쌍도 포함하므로 처음 보면 이상하게 읽힙니다.
  • 배치 전체가 거부되는 경우는 뻔한 세 가지보다 많습니다. 요청 25개 초과, 400 KB를 넘는 항목, 합계 16 MB 초과와 더불어, 존재하지 않는 테이블, 스키마와 맞지 않는 키, 2048바이트를 넘는 파티션 키, 1024바이트를 넘는 정렬 키에 대해서도 DynamoDB는 배치를 거부합니다. 잘못된 항목 하나가 25개 전부를 날립니다.
  • 배치는 왕복 횟수를 줄여 줄 뿐 용량을 아껴 주지는 않습니다. 각 항목은 개별 PutItem이나 DeleteItem으로 1 KB 단위 올림 청구되며, 존재하지 않는 항목을 겨냥한 삭제도 쓰기 단위를 소비합니다.

키만 담은 PutRequest는 항목의 나머지를 지웁니다

Ella Fitzgerald / Misty는 처음에 AlbumTitleYear를 가지고 있습니다. 여기에 키 속성 두 개만 담은 PutRequest를 하나 보내 보세요:

{PutRequest: {Item: {Artist: {S: 'Ella Fitzgerald'}, SongTitle: {S: 'Misty'}}}}

그런 다음 ConsistentRead: true로 다시 읽습니다. DynamoDB Local 3.3.0은 이렇게 반환합니다:

{
  "Artist": { "S": "Ella Fitzgerald" },
  "SongTitle": { "S": "Misty" }
}

AlbumTitleYear가 사라졌습니다. 호출은 성공했고, UnprocessedItems{}였으며, 응답 어디에도 버려진 두 속성에 대한 언급이 없습니다. put은 항목 전체를 교체하므로, 부분적인 페이로드(API 요청 본문, CSV 열의 일부, 속성을 누락한 프로젝션 Query 결과)로 조립한 배치는 그 페이로드에 없던 모든 속성을 지워 버립니다.

업데이트처럼 느껴지는 일에 배치를 쓸 때 대비해야 할 실패 양상이 바로 이것입니다. 해결책은 현재 항목을 먼저 읽어 병합하거나, 배치를 그만두고 지정한 속성만 건드리는 UpdateItem을 쓰는 것입니다.

25개짜리 배치가 12개짜리 배치가 되는 또 다른 이유는 크기입니다. 쓰기는 청구 시 각각 1 KB 단위로 올림되고 요청은 16 MB에서 상한에 걸리므로, 항목의 실제 바이트 수가 요금과 배열에 몇 개가 들어가는지를 함께 결정합니다. 항목 크기 계산기는 배열을 조립하기 전에 항목별로 그 숫자를 알려 줍니다.

교체 의미론을 손으로 챙기지 않고도 항목을 대량으로 불러오고 편집하고 삭제하려면 DynoTable을 다운로드하세요.

관련 예제

참고 자료

위에 링크된 공식 AWS 문서를 기준으로 2026-07-28에 마지막으로 검증했습니다.

Console 없이 DynamoDB 작업하기

DynamoDB로는 실행할 수 없는 진짜 SQL(JOINs, GROUP BY, 집계)을 실행하는 빠른 DynamoDB 데스크톱 클라이언트. 시각적 편집과 여러분 자신의 Bedrock 키로 동작하는 AI 에이전트를 제공합니다.

30일 무료 체험, 신용카드 불필요 — 이후 기간 제한 없는 무료 요금제.