Escrita condicional no DynamoDB com a AWS CLI

Uma escrita condicional é simples de enviar pelo shell e desconfortável de ler, porque o resultado interessante de uma que falha chega como erro, e não como saída. Expressões de condição do DynamoDB cobre o que a expressão pode dizer; esta página é sobre executar uma pela CLI e extrair da falha o item perdedor.

Código

aws dynamodb update-item \
  --table-name 'Music' \
  --key '{"Artist":{"S":"Arturo Sandoval"},"SongTitle":{"S":"Cubano Chant"}}' \
  --update-expression 'SET #upd0 = :updValue0, #version = :newVersion' \
  --condition-expression 'attribute_exists(#cond0) AND #version = :expectedVersion' \
  --expression-attribute-names '{"#upd0":"Genre","#version":"Version","#cond0":"Artist"}' \
  --expression-attribute-values '{":updValue0":{"S":"Latin Jazz"},":expectedVersion":{"N":"7"},":newVersion":{"N":"8"}}'

Em caso de sucesso o comando não imprime nada e sai com 0. Se outro escritor chegou primeiro, a condição falha e a CLI reporta a mensagem do serviço:

An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation:
The conditional request failed

Explicação

  • O sucesso é silencioso. Sem saída, código de saída 0. Não há nada para fazer parse nem nada para verificar, então um script de shell tem que tratar o código de saída como o resultado. Adicione --return-values ALL_NEW se você quiser o item atualizado impresso.
  • A falha é o código de saída 254, que é o código da CLI v2 para um erro do lado do cliente e é compartilhado com uma requisição malformada. Ramifique com base na mensagem antes de tentar novamente, ou um erro de digitação na sua expressão vira um loop de backoff infinito.
  • --return-values-on-condition-check-failure ALL_OLD funciona aqui, sim. Os valores válidos são ALL_OLD e NONE, e ele não consome capacidade de leitura. Extrair o item do erro exige mais uma flag, coberta abaixo.
  • A condição e a atualização são flags separadas com um namespace compartilhado. --expression-attribute-names e --expression-attribute-values são mesclados entre --update-expression e --condition-expression, e é por isso que os nomes gerados vão de #upd0 a #cond0 em vez de recomeçar por cláusula. Reutilize um placeholder para dois significados diferentes e o segundo vence silenciosamente.
  • Uma escrita que falha ainda é cobrada. O Developer Guide é explícito: uma condição que avalia como falsa consome capacidade de escrita de qualquer forma, dimensionada pelo maior entre o item antigo e o novo. Condições não são uma sondagem barata de existência.

A saída da falha, e como extrair o item dela

Execute o bloco uma vez e ele tem sucesso silenciosamente. Execute-o uma segunda vez, quando Version não é mais 7, e a aws-cli/2.36.9 imprime no stderr:

aws: [ERROR]: An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation: The conditional request failed

Adicione --return-values-on-condition-check-failure ALL_OLD e a saída padrão te avisa que há mais, sem mostrar:

aws: [ERROR]: An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation: The conditional request failed

Additional error details:
Item: <complex value>
Use "--cli-error-format json" or another error format to see the full details.

<complex value> é o item, retido pelo renderizador de texto padrão. Adicione --cli-error-format json e a coisa toda é impressa:

{
    "Message": "The conditional request failed",
    "Code": "ConditionalCheckFailedException",
    "Item": {
        "Artist": {"S": "Arturo Sandoval"},
        "Year": {"N": "1994"},
        "Version": {"N": "8"},
        "SongTitle": {"S": "Cubano Chant"},
        "AlbumTitle": {"S": "Danzon"},
        "Genre": {"S": "Latin Jazz"}
    }
}

(Mapas de atributos dobrados em uma linha cada; todo o resto é como foi impresso.) Version é 8 e Genre está definido porque a primeira execução teve sucesso. Esse é o loop de bloqueio otimista fechado a partir de um script de shell: encaminhe o stderr por jq -r '.Item.Version.N', devolva o valor como :expectedVersion, tente de novo. Sem get-item, e sem janela entre a leitura e a nova tentativa para um terceiro escritor se enfiar.

As novas tentativas não são de graça. Cada tentativa rejeitada consome uma unidade de escrita, então uma chave disputada em um loop apertado é cobrada continuamente sem fazer progresso algum. A calculadora de preços transforma uma taxa de escrita em um valor mensal se você quiser saber quanto uma tempestade de retries custa de verdade antes de limitar as tentativas.

Para executar essas proteções contra as suas próprias tabelas sem escapar os mapas de placeholders no shell, 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.