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

O cliente de baixo nível da v3 fala DynamoDB JSON nas duas direções, o que significa que todo número que você envia e todo número que recebe de volta é uma string. Isso não é um defeito; é a única forma de um número de 38 dígitos do DynamoDB sobreviver a uma linguagem cujo único tipo numérico é um double. É também onde estão os bugs.

Código

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

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

const command = new UpdateItemCommand({
  TableName: 'Music',
  Key: {
    Artist: {S: 'Arturo Sandoval'},
    SongTitle: {S: 'Cubano Chant'}
  },
  UpdateExpression: 'SET #upd0 = :updValue0, #upd1 = :updValue1 ADD #upd2 :updValue2',
  ExpressionAttributeNames: {
    '#upd0': 'Genre',
    '#upd1': 'Year',
    '#upd2': 'Awards'
  },
  ExpressionAttributeValues: {
    ':updValue0': {S: 'Latin Jazz'},
    ':updValue1': {N: '1994'},
    ':updValue2': {N: '1'}
  },
  ReturnValues: 'ALL_NEW'
});

const response = await client.send(command);
console.log(response.Attributes); // the item after the update

Contra um item que não tinha Genre nem Awards, o response.Attributes volta assim:

{"Artist":{"S":"Arturo Sandoval"},"Awards":{"N":"1"},"Genre":{"S":"Latin Jazz"},"Year":{"N":"1994"},"SongTitle":{"S":"Cubano Chant"}}

typeof response.Attributes.Awards.N é "string", então response.Attributes.Awards.N + 1 resulta em "11". Nada lança erro, nada avisa, e o número errado entra na sua próxima escrita. Faça o parsing na fronteira: Number(response.Attributes.Awards.N).

Explicação

  • A expressão é uma string simples, e a v3 não vai verificá-la. O UpdateItemCommand valida o formato do objeto de entrada, nunca a gramática dentro de UpdateExpression, então um erro de digitação é uma ida e volta e um 400. A gramática está em expressões de atualização; ADD #upd2 :updValue2 é o incremento atômico, e adicionar ConditionExpression: 'attribute_exists(Artist)' faz a chamada ser só-atualização em vez de upsert.

  • ReturnValues: 'UPDATED_NEW' costuma ser o que você quer. A mesma atualização retorna {"Awards":{"N":"2"}} e nada mais. O ALL_NEW manda o item inteiro de volta a cada chamada, o que, em um item gordo, é banda que você paga para ler um contador.

  • $metadata é o canal fora de banda da v3: {"httpStatusCode":200,"requestId":"...","attempts":1,"totalRetryDelay":0}. O attempts é a resposta honesta para "isso foi retentado?", o que importa quando você está raciocinando sobre se uma escrita não idempotente rodou duas vezes.

  • ValidationException não é uma classe que você possa capturar, só um name que você pode comparar. Um alias faltando volta como err.name === 'ValidationException' com err.message igual a Invalid UpdateExpression: Attribute name is a reserved keyword; reserved keyword: Year.

  • O document client é a outra troca. O @aws-sdk/lib-dynamodb recebe valores nativos de JS e faz unmarshal da resposta, ao custo daquela segurança das strings. O marshall({awards: 9007199254740993}) do @aws-sdk/util-dynamodb recusa de imediato:

    Number 9007199254740992 is greater than Number.MAX_SAFE_INTEGER. Use NumberValue from @aws-sdk/lib-dynamodb.

    Olhe bem para o número nessa mensagem. Ele termina em 2, não no 3 que foi escrito no literal: o JavaScript já o havia arredondado antes de o SDK sequer vê-lo. O cliente de baixo nível deste trecho não pode ter esse problema, porque {N: '9007199254740993'} é texto até chegar na rede.

O que uma condição que falha te entrega

Adicione ReturnValuesOnConditionCheckFailure: 'ALL_OLD' à entrada e o erro lançado carrega o item que te venceu:

name: ConditionalCheckFailedException | message: "The conditional request failed" | http: 400
err.Item: {"Artist":{"S":"Arturo Sandoval"},"Awards":{"N":"2"},"Year":{"N":"1994"},"SongTitle":{"S":"Cubano Chant"},"Genre":{"S":"Latin Jazz"}}

O err.Item é DynamoDB JSON cru, não importa qual cliente o lançou, e ele é grátis. Sem ele, a forma honesta de descobrir por que uma atualização com concorrência otimista falhou é um GetItem de acompanhamento que custa uma leitura e já pode estar desatualizado de novo.

O conversor de DynamoDB JSON transforma esse payload em um objeto JS simples e de volta, que é a forma mais rápida de montar um fixture a partir de um item real. Para tirar esse item de uma tabela ao vivo, para começar, baixe o DynoTable.

Guias 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.