DynamoDB Expressões de condição: o guia completo (com exemplos)
Uma expressão de condição é um predicado DynamoDB avaliado no item existente
antes de confirmar sua gravação. Se o predicado for falso, a gravação é
rejeitado e nada muda. É a coisa mais próxima que DynamoDB tem de um
Cláusula WHERE em uma gravação - e a única maneira segura de impor uma invariante.
Como funcionam as expressões de condição DynamoDB?
Uma expressão de condição é um predicado DynamoDB que avalia o lado do servidor em relação ao item atual antes de confirmar uma gravação. Se for verdade, a gravação prossegue; se for falso, a gravação é rejeitada com ConditionalCheckFailedException e nada muda. Ele reúne a verificação e a mutação em uma operação atômica, para que os chamadores simultâneos não possam competir com uma leitura obsoleta.
- É um protetor, não um filtro.
ConditionExpressionroda no lado do servidor item atual; um resultado falso falha na gravação comConditionalCheckFailedException. - Ele substitui leitura e gravação. Sem
SELECTe depoisUPDATEde ida e volta - o check e a mutação são uma operação atômica, portanto, dois chamadores não podem competir. - É gratuito para rejeitar, não é gratuito para executar. Uma gravação condicional com falha ainda consome capacidade de gravação. Uma nota de emissão rejeitada WCUs para o tamanho do item existente com o qual foi verificado (mínimo 1) — uma falha na criação se estiver ausente custa 1 WCU.
Vindo de SQL, você leria a linha, verificaria no código do aplicativo e atualizaria. Em DynamoDB essa lacuna entre leitura e gravação é um bug de corrupção de dados esperando por um chamador simultâneo. A expressão de condição fecha a lacuna.
Onde eles se aplicam
Você anexa um ConditionExpression a PutItem, UpdateItem, DeleteItem e
cada ação dentro de TransactWriteItems. não faz parte de Query ou Scan
- esses usam
FilterExpression, que é uma coisa diferente no caminho de leitura.
Essa distinção confunde as pessoas, então seja preciso:
ConditionExpression | FilterExpression | |
|---|---|---|
| Caminho | Grava (Put/Update/Delete) | Lê (Query/Scan) |
| Efeito na falha | Rejeita toda a gravação | Elimina o item dos resultados |
| Vê | O item atual, pré-gravação | Cada item candidato, pós-leitura |
| Custo | Falha ao escrever contas ainda | Os itens filtrados ainda são cobrados pela leitura |
Ambos são executados no lado do servidor. A diferença é o que “false” faz: uma condição aborta uma mutação; um filtro apenas oculta uma linha que você já pagou para ler. (AWS: Expressões de condição)
As funções que você realmente usará
A linguagem da condição é pequena. Os burros de carga:
attribute_exists(path)/attribute_not_exists(path)— faz isso
existe no item? A expressão clássica para "criar somente se estiver ausente" / "atualizar somente se presente".
- Comparadores —
=,<>,<,<=,>,>=— contra um valor ou outro atributo. attribute_type,begins_with,contains,size— verificações de tipo e string/conjunto.ENTRE… E …,IN (...)— alcance e associação.AND,OR,NOT, parênteses — para combinar o acima.
attribute_not_exists noé a maneira canônica de fazer
PutItem se comporta como uma inserção que não atrapalha um item existente — DynamoDB
não tem operação de "inserção" separada, portanto a condição é a semântica de inserção.
(AWS: Operador de comparação e referência de função)
Um exemplo prático: proteger um livro-razão contra cheque especial
Pegue um livro-razão bancário. Cada conta é um item:
PK = "ACCT#a7f3"
SK = "BALANCE"
clearedCents = 50000
holdCents = 0Um débito nunca deve empurrar o saldo disponível abaixo de zero, e você nunca deve debitar uma conta que não existe. Duas regras, ambas aplicáveis em a escrita em si.
O caminho errado (a arma)
GetItem ACCT#a7f3 / BALANCE → clearedCents = 50000
if (50000 >= 30000) ... ← app-side check
UpdateItem SET clearedCents = 20000
Entre GetItem e UpdateItem, um segundo débito pode ler o mesmo
50000, passe seu próprio cheque e escreva também. Ambos têm sucesso; a conta vai
negativo. Esta é uma corrida de leitura-modificação-gravação e nenhuma validação do lado do aplicativo
corrige isso - a verificação e a gravação são operações separadas.
O jeito certo
Dobre o cheque para escrever. Débito 30.000 centavos, condicionado à conta existente e mantendo o suficiente:
UpdateItem ACCT#a7f3 / BALANCE
SET clearedCents = clearedCents - :amt
ConditionExpression:
attribute_exists(PK) AND clearedCents >= :amtcom :amt = 30000. Se o saldo for muito baixo ou o item nunca tiver sido criado,
DynamoDB rejeita a gravação com
ConditionalCheckFailedException
e o equilíbrio
está intocado. O débito simultâneo vê o saldo original e é
verificado em relação a ele ou vê o atualizado - nunca uma leitura obsoleta que agiu.
Você pode construir e copiar a expressão exata – nomes, valores e tudo – com o
DynamoDB construtor de expressão em vez de
montando manualmente o mapa ExpressionAttributeValues.
Experimente aqui - este construtor está predefinido para um PutItem protegido
(attribute_not_exists) para que você possa ler o ConditionExpression gerado:
Inspecionando o guarda em DynoTable
Quando uma gravação condicional falha, você deseja ver o estado real do item, e não adivinhar
nisso. Puxe o item da conta para cima e leia clearedCents diretamente.

Leia a rejeição, não tente novamente cegamente
ConditionalCheckFailedException não é um erro transitório - tentar novamente o mesmo
escrever não muda nada. Significa que uma regra de negócios foi acionada: fundos insuficientes,
criação duplicada, versão obsoleta. Mostre isso como um resultado de domínio, não um infra
pontinho.
Duas coisas tornam as falhas depuráveis:
ReturnValuesOnConditionCheckFailure: ALL_OLD— DynamoDB retorna o item atual ao lado da falha, para que você possa mostrar "o saldo era 20.000, você pediu 30.000" sem uma segunda leitura. (AWS: Trabalhando com itens)- Distinguindo os dois motivos de falha.
attribute_exists(PK) AND clearedCents >= :amtreúne "sem conta" e "sem fundos" em um exceção. Se os chamadores precisarem diferenciá-los, divida-os em duas gravações ou inspecione o item devolvido.
O bloqueio otimista é o mesmo truque
O padrão de número de versão é apenas uma expressão de condição com um formato diferente
chapéu. Armazene um atributo versão; cada gravação afirma a versão que você lê e
bate:
UpdateItem ACCT#a7f3 / BALANCE
SET clearedCents = :new, version = :next
ConditionExpression: version = :seenSe outro escritor se moveu primeiro, version = :seen é falso, a gravação é rejeitada,
e você relê e tenta novamente. É assim que DynamoDB faz o controle de simultaneidade sem
fechaduras – afirme o que você viu, falhe se ele se mover. (AWS: Bloqueio Otimista com
Número da versão)
A área de teste do DynoTable executa esse padrão para você - um
a edição simultânea surge como um conflito a ser resolvido, não como uma gravação perdida.
Armadilhas e próximos passos
- Nomes que colidem com palavras reservadas.
status,size,namee ~570 outros são reservados. Alias eles comExpressionAttributeNames(#s = status) ou a solicitação é rejeitada com uma ValidationException ('Nome do atributo é um palavra-chave reservada'). O verificador de palavras reservadas pega seu nomes de atributos e devolve o mapa de alias pronto para colar. - Uma condição não pode fazer referência a outro item. Ela apenas vê o item sendo
escrito. Invariantes entre itens precisam de
TransactWriteItemscom uma ação por açãoConditionExpression, ou umConditionCheckcontra um item sentinela. - Escritas com falha ainda custam WCUs. Um guarda que rejeita 90% das vezes ainda contas para essas rejeições. Seguro barato, mas não gratuito.
Para modelar as chaves contra as quais esses guardas são executados, consulte design de tabela única e Query vs Scan. Quando você estiver pronto para emitir condições escreve em dados reais, download DynoTable e executa-os em suas próprias mesas.


