BatchWriteItem do DynamoDB em Node.js (AWS SDK v3)

O BatchWriteItem grava ou apaga até 25 itens em uma requisição. Ele não é um UpdateItem menor: todo PutRequest substitui o item armazenado inteiro, e os tipos da v3 não te dão onde anexar uma condição. Operações em lote no DynamoDB cobre os limites e o modelo de falha parcial; esta página é sobre a chamada v3 e sobre a única forma pela qual ela perde dados silenciosamente.

Código

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');

Explicação

  • O campo dos restos é UnprocessedItems, não UnprocessedKeys. O lado da leitura usa o outro nome, e em JavaScript um erro de digitação aqui compila, é lido como undefined e transforma o do/while em uma chamada de passagem única que joga fora as escritas com throttle. O TypeScript pega isso; o JS puro não.
  • Não há onde colocar uma condição. O tipo WriteRequest da v3 tem exatamente dois campos opcionais, PutRequest e DeleteRequest, e nenhum aceita ConditionExpression nem ReturnValues. Não é o SDK sendo conservador: a referência da API diz que você não pode especificar condições em requisições individuais de put e delete. Se uma escrita precisa de uma guarda, ela não pertence a um lote — pertence a um UpdateItem com condição ou a uma transação.
  • Dois erros passíveis de catch, ambos não retentáveis, discriminados por err.name. Vinte e seis entradas geram ValidationException / Too many items requested for the BatchWriteItem call. Tocar a mesma chave duas vezes gera Provided list of item keys contains duplicates, e essa mensagem cobre tanto um par put+delete quanto dois puts, o que soa estranho na primeira vez que você a vê.
  • A lista de rejeições do lote inteiro é maior que as três óbvias. Além de mais de 25 requisições, um item acima de 400 KB e um total acima de 16 MB, o DynamoDB recusa o lote por tabela inexistente, por uma chave que não corresponde ao schema, por uma chave de partição acima de 2048 bytes ou por uma chave de classificação acima de 1024 bytes. Uma entrada ruim te custa as 25.
  • Agrupar em lote compra idas e voltas, não capacidade. Cada entrada é cobrada como um PutItem ou DeleteItem individual, arredondado para cima a cada 1 KB, e um delete mirado em um item inexistente ainda consome uma unidade de escrita.

Um PutRequest só com a chave destrói o resto do item

Ella Fitzgerald / Misty começa com um AlbumTitle e um Year. Envie um PutRequest levando apenas os dois atributos de chave:

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

Depois leia de volta com ConsistentRead: true. O DynamoDB Local 3.3.0 retorna:

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

AlbumTitle e Year sumiram. A chamada teve sucesso, UnprocessedItems veio {} e nada na resposta menciona os dois atributos que ela descartou. Um put é uma substituição do item inteiro, então um lote montado a partir de um payload parcial (o corpo de uma requisição de API, um subconjunto de colunas de CSV, o resultado de um Query projetado que omitiu atributos) apaga todo atributo que o payload não carregava.

Esse é o modo de falha a prever quando você usa um lote para o que parece uma atualização. A correção é ler o item atual primeiro e mesclar, ou parar de usar lote e usar UpdateItem, que toca apenas os atributos que você nomear.

O outro motivo pelo qual um lote de 25 itens vira um lote de 12 é o tamanho. As escritas arredondam para cima a cada 1 KB na cobrança e a requisição tem teto de 16 MB, então a contagem real de bytes de um item decide tanto a sua conta quanto quantos cabem. A calculadora de tamanho de item te dá esse número por item antes de você montar o array.

Para carregar, editar e apagar itens em massa sem escrever à mão a semântica de substituição, baixe o DynoTable.

Exemplos relacionados

Referências

Verificado pela última vez em 2026-07-28 contra a documentação oficial da AWS vinculada acima.

Trabalhe com o DynamoDB sem o Console

Um cliente desktop rápido para DynamoDB que roda o SQL de verdade que o DynamoDB não consegue — JOINs, GROUP BY, agregações — com edição visual e um agente de IA com suas próprias chaves do Bedrock.

Teste grátis de 30 dias, sem cartão de crédito — depois o plano Grátis sem limite de tempo.