Intermediário5 min de leitura

Expressões de atualização DynamoDB: SET, REMOVE, ADD, DELETE (com exemplos)

Uma expressão de atualização informa ao UpdateItem como transformar um único item: qual para escrever, incrementar, excluir ou dobrar em um conjunto. Não há várias linhas UPDATE … SET … WHERE — você nomeia um único item pela sua chave completa e descreve o mude com palavras-chave de quatro cláusulas.

Como funcionam as expressões de atualização do DynamoDB?

Uma expressão de atualização DynamoDB informa ao UpdateItem como alterar um item usando quatro cláusulas. SET grava ou substitui um . ADD incrementa atomicamente um número ou uniões em um conjunto. REMOVE exclui um atributo ou um elemento da lista. DELETE remove membros específicos de um conjunto. Uma chamada pode transportar todos os quatro de uma vez.

  • SET grava ou sobrescreve um atributo — escalares, documentos e idiomas de função if_not_exists e list_append.
  • ADD faz um incremento de número atômico ou uma união de conjunto, em uma viagem de ida e volta, sem leitura inicial.
  • REMOVE exclui um atributo imediatamente (ou um único elemento da lista por índice).
  • DELETE remove membros específicos de um conjunto — e somente de um conjunto.

Vindo do SQL, a armadilha chega ao SET para tudo. ADD e DELETE existe porque ler-modificar-escrever em um contador ou conjunto é uma corrida que você perder sob concorrência.

Escolha a cláusula de acordo com o que você está alterando

Uma chamada UpdateItem pode transportar todas as quatro cláusulas de uma vez, em qualquer ordem. Cada palavra-chave aparece no máximo uma vez e leva uma lista de ações separadas por vírgula.

CláusulaFunciona emUse-o para
SETQualquer atributoWrite/overwrite um valor ou campo de documento
ADDSomente número ou conjuntoIncremento atomicamente ou união em um conjunto
REMOVEQualquer atributo ou elemento de listaExclua um atributo; eliminar um índice de lista
DELETEDefinir apenasRemover membros específicos de um conjunto

ADD em uma string e DELETE em um escalar são erros de validação, não no-ops - DynamoDB rejeita toda a chamada. De acordo com Referência de expressão de atualização AWS, O ADD está restrito a números e conjuntos, e o DELETE a conjuntos.

O exemplo resolvido: um carrinho de compras

Um item por carrinho, codificado por CartPK = "CART#c-9f21" e CartSK = "SUMMARY". Ele rastreia um OrderTotal em execução, uma lista LineItems, um conjunto de strings PromoCodes, e um ItemCount.

SET — escreve os escalares e documentos

SET substitui tudo o que estava lá. Adicione um item de linha à lista e aumente o total na mesma chamada:

SET OrderTotal = :total,
LineItems = list_append(LineItems, :newItem),
UpdatedAt = :now

list_append(LineItems, :newItem) é anexado à cauda; inverta os argumentos - list_append(:newItem, LineItems) — para preceder. A ordem dos argumentos é a ordem de concatenação, nada mais.

Há uma arma de fogo naquela primeira ligação: se o carrinho for novo, LineItems ainda não existe e o list_append falha em um atributo ausente. Guarde-o com if_not_exists:

SET LineItems = list_append(if_not_exists(LineItems, :empty), :newItem)

if_not_exists(LineItems, :empty) retorna a lista atual, se presente, caso contrário, o fallback :empty (uma lista vazia []). Isso faz com que a primeira adição e depois add use a mesma expressão - uma verdadeira razão pela qual essas expressões existem.

ADD — incrementa a contagem, atomicamente

Para bater o ItemCount, não leia, adicione um em seu código e SET de volta. Essa é uma corrida de atualização perdida: duas adições simultâneas leem 3, ambas escrevem 4 e você deixou cair um. ADD faz a aritmética no lado do servidor:

ADD ItemCount :one

Com :one = 1, este é um contador atômico. Chamadas simultâneas são serializadas no item, então dois adicionam terreno como +2. Passe um número negativo para decrementar. Se ItemCount está ausente, ADD trata-o como 0 primeiro – então você nunca precisa semear o contador.

Sob demanda no us-east-1, cada ADD cobra 1 WCU por KB do item após a gravação (arredondada). Um resumo do carrinho de 1 KB com custos de um ADD ItemCount :one 1 WCU — a mesma linha com um SET de leitura-modificação-gravação custaria o mesmo WCU mas perde sob concorrência. Dimensione o item no calculadora de tamanho de item.

Você pode construir esta expressão exata - nomes, valores digitados e o empacotamento solicitação - no Construtor de expressão DynamoDB sem escapar manualmente de um único espaço reservado #name ou :value.

Edite o preset abaixo - um SET mais um ADD atômico - e assista ao UpdateExpression reconstruído conforme você avança:

Monte sua requisição
Código gerado
new UpdateItemCommand({
  "TableName": "AuditLog",
  "Key": {
    "pk": {
      "S": "TENANT#acme"
    },
    "sk": {
      "S": "CONFIG"
    }
  },
  "UpdateExpression": "SET #upd0 = :updValue0 ADD #upd1 :updValue1",
  "ExpressionAttributeNames": {
    "#upd0": "plan",
    "#upd1": "seats"
  },
  "ExpressionAttributeValues": {
    ":updValue0": {
      "S": "pro"
    },
    ":updValue1": {
      "N": "5"
    }
  }
})

REMOVE — elimina um atributo ou um item de linha

REMOVE é como você exclui totalmente um atributo (não há "defini-lo como nulo" - que apenas escreve um tipo NULL). Limpe um desconto aplicado e descarte o terceiro item de linha em uma chamada:

REMOVE AppliedDiscount, LineItems[2]

LineItems[2] remove o elemento no índice 2 e muda tudo depois dele para baixo — o índice 3 se torna 2 e assim por diante. Se você usar REMOVE em dois índices em uma expressão, ambos são avaliados em relação à lista original, portanto remover [2] e [3] juntos elimina o terceiro e o quarto elementos como seria de esperar.

DELETE — remove membros do conjunto

PromoCodes é um conjunto de strings, portanto, um cliente que obtém um código usa DELETE, não REMOVE. REMOVE PromoCodes destruiria todo o conjunto; DELETE subtrai o membros nomeados:

DELETE PromoCodes :pulled

Com :pulled = o conjunto {"SAVE10"}, apenas esse membro vai. Duas regras mordem aqui: um conjunto nunca pode estar vazio, então excluir o último membro remove o Atributo PromoCodes definitivo; e o valor deve ser um tipo de conjunto correspondente ao atributo - uma string vazia é um erro de tipo.

Junte tudo

Uma atualização "adicionar item, aplicar uma promoção, aumentar a contagem" é uma chamada entre três cláusulas:

SET LineItems = list_append(if_not_exists(LineItems, :empty), :newItem),
OrderTotal = OrderTotal + :price
ADD ItemCount :one
DELETE PromoCodes :expiredCode

Nota OrderTotal = OrderTotal + :price - aritmética dentro de SET funciona no valor existente. É tão atômico e seguro para corridas quanto o ADD: avalia o DynamoDB OrderTotal + :price do lado do servidor em relação ao valor atual, portanto, chamadas simultâneas serialize no item em vez de percorrer seu código.

Armadilhas a evitar

  • SET-ing um contador que você lê primeiro. Use ADD - leitura-modificação-gravação perde atualizações sob simultaneidade. Este é o bug cart/inventory mais comum.
  • list_append em uma lista ausente. Envolva o alvo em if_not_exists ou no a primeira gravação falha.
  • Confundir REMOVE e DELETE. REMOVE elimina o atributo; DELETE subtrai membros de um conjunto. Misturá-los exclui mais do que você pretendia.
  • Esquecer UpdateItem é um upsert. Se a chave não existir, ela cria o item. Use um ConditionExpression (attribute_exists(CartPK)) quando você significa "somente atualização".

Para modelar as chaves nas quais essas expressões são executadas, consulte design de mesa única; para decidir como você vai ler o carrinho de volta, consulte query vs scan.

Construa e copie qualquer um deles no construtor de expressão, então experimente DynoTable para executá-los em suas próprias mesas e observe o item mudar ao vivo.

Atualizado