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

O BatchGetItem busca até 100 itens por chave primária em uma requisição. No AWS SDK v3 a chamada precisa ser um laço, porque UnprocessedKeys chega em uma resposta bem-sucedida, e não em um erro. O que preenche esse campo, e por que 16 MB e 1 MB por partição são os números que importam, está em operações em lote no DynamoDB. Esta página é sobre a chamada v3 e sobre o que ela devolve.

Código

import {BatchGetItemCommand, 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: {
    Keys: [
      {Artist: {S: 'Arturo Sandoval'}, SongTitle: {S: 'Cubano Chant'}},
      {Artist: {S: 'Arturo Sandoval'}, SongTitle: {S: 'A Mis Abuelos'}},
      {Artist: {S: 'Ella Fitzgerald'}, SongTitle: {S: 'Misty'}}
    ]
  }
};

const items = [];
let attempt = 0;

do {
  const response = await client.send(new BatchGetItemCommand({RequestItems: requestItems}));
  items.push(...(response.Responses?.Music ?? []));

  // A partial result is NOT an error: throttling, a >16 MB response, or an
  // internal failure returns the leftovers in UnprocessedKeys. Retry them
  // with exponential backoff.
  requestItems = response.UnprocessedKeys;
  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(`Fetched ${items.length} items`);

Explicação

  • O encadeamento opcional não é ruído defensivo. Responses e UnprocessedKeys são ambos opcionais nos tipos da v3, então response.Responses?.Music ?? [] e a guarda com Object.keys() são o que o compilador exige. Em JavaScript puro, são o que impede a primeira resposta vazia de lançar erro.
  • Ramifique com base em err.name. A v3 coloca ali o código de erro do serviço, e as duas falhas que este comando de fato gera não são retentáveis, então elas nunca podem cair no laço de backoff. Mais de 100 chaves dão ValidationException / Too many items requested for the BatchGetItem call; a mesma chave duas vezes dá Provided list of item keys contains duplicates. Ambas estão reproduzidas literalmente na página de Python.
  • UnprocessedKeys já chega no formato de RequestItems, que é a única razão pela qual o laço consegue reatribuí-lo direto. Não é um cursor de paginação e não significa que a chamada falhou.
  • O backoff é uma instrução da AWS, não um capricho. A referência da API manda usar "an exponential backoff algorithm" porque um retry imediato cai na mesma partição com throttle.
  • ConsistentRead e ProjectionExpression são por tabela, definidos dentro de cada entrada de RequestItems e não no nível superior. Isso é fácil de deixar passar quando o mapa tem uma chave só e parece uma requisição plana.

Como a resposta volta de fato

Rode o bloco acima no DynamoDB Local 3.3.0 com as três músicas presentes, acrescente ReturnConsumedCapacity: 'TOTAL' e imprima os títulos das músicas em vez da contagem:

order:            [ 'A Mis Abuelos', 'Misty', 'Cubano Chant' ]
UnprocessedKeys:  {}
ConsumedCapacity: [ { TableName: 'Music', CapacityUnits: 1.5 } ]

A requisição listou Cubano Chant, A Mis Abuelos, Misty. A resposta não está em nenhuma dessas posições, e é por isso que o laço empurra tudo para um array plano em vez de indexar por posição. Case os itens de volta com as requisições pelos atributos de chave, e inclua essas chaves em qualquer ProjectionExpression para você ainda ter algo com que casar.

Defina ConsistentRead: true nessa mesma entrada de Music e as mesmas três chaves custam 3 unidades em vez de 1,5. Três itens abaixo de 4 KB cada são cobrados como três leituras GetItem separadas, a meia unidade com consistência eventual e uma unidade inteira com consistência forte. A calculadora de preços converte essa aritmética por item em um número mensal antes de você se comprometer com um padrão de leitura.

Agora apague Misty e rode de novo: dois itens, um UnprocessedKeys vazio e 1,0 unidade. A chave ausente não foi cobrada. Isso é um artefato do DynamoDB Local, não o contrato; a referência do BatchGetItem (consultada em 2026-07-28) diz que requisições de itens inexistentes consomem a capacidade de leitura mínima para o tipo de leitura. Não dimensione um lote de cache misses a partir de uma execução local.

Para puxar um conjunto de chaves de volta e olhar o que realmente retornou, sem antes escrever o laç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.