Update expression in DynamoDB
Una update expression dice a UpdateItem come mutare un singolo item: quali
attributi scrivere, incrementare, eliminare o fondere in un set. Non c'è
UPDATE … SET … WHERE — nomini l'item tramite la sua chiave e descrivi il
cambiamento con quattro parole chiave di clausola.
Come funzionano le update expression di DynamoDB?
Una update expression di DynamoDB dice a UpdateItem come mutare un item usando quattro clausole. SET scrive o sovrascrive un . ADD incrementa atomicamente un numero o unisce in un set. REMOVE elimina un attributo o un elemento di lista. DELETE rimuove membri specifici da un set. Una sola chiamata può portare tutte e quattro insieme.
SETscrive o sovrascrive un attributo — scalari, documenti e gli idiomi funzioneif_not_existselist_append.ADDfa un incremento numerico atomico o un'unione di set, in un solo round trip, senza leggere prima.REMOVEelimina del tutto un attributo (o un singolo elemento di lista per indice).DELETErimuove membri specifici da un set — e solo da un set.
Venendo da SQL, la trappola è ricorrere a SET per tutto. ADD e DELETE
esistono perché il read-modify-write su un contatore o un set è una gara che
perderai sotto concorrenza.
Scegli la clausola in base a cosa stai cambiando
Una sola chiamata UpdateItem può portare tutte e quattro le clausole insieme,
nell'ordine SET … REMOVE … ADD … DELETE. Ogni parola chiave compare al massimo
una volta e prende un elenco di azioni separate da virgola.
| Clausola | Funziona su | Usala per |
|---|---|---|
SET | Qualsiasi attributo | Scrivere/sovrascrivere un valore o un campo documento |
ADD | Solo Number o Set | Incrementare atomicamente, o unire in un set |
REMOVE | Qualsiasi attributo o elemento di lista | Eliminare un attributo; togliere un indice di lista |
DELETE | Solo Set | Rimuovere membri specifici da un set |
ADD su una stringa e DELETE su uno scalare sono errori di validazione, non
no-op — DynamoDB rifiuta l'intera chiamata. Secondo il
riferimento update-expression di AWS,
ADD è ristretto a numeri e set, e DELETE ai set.
L'esempio pratico: un carrello della spesa
Un item per carrello, con chiave CartPK = "CART#c-9f21" e CartSK = "SUMMARY".
Traccia un OrderTotal corrente, una lista LineItems, un set di stringhe
PromoCodes e un ItemCount.
SET — scrivi gli scalari e i documenti
SET sovrascrive qualunque cosa ci fosse. Aggiungi un line item alla lista e
incrementa il totale nella stessa chiamata:
SET OrderTotal = :total,
LineItems = list_append(LineItems, :newItem),
UpdatedAt = :now
list_append(LineItems, :newItem) aggiunge in coda; inverti gli argomenti —
list_append(:newItem, LineItems) — per anteporre. L'ordine degli argomenti è
l'ordine di concatenazione, nient'altro.
C'è un footgun in quella prima chiamata: se il carrello è nuovissimo, LineItems
non esiste ancora, e list_append su un attributo mancante fallisce. Proteggilo
con if_not_exists:
SET LineItems = list_append(if_not_exists(LineItems, :empty), :newItem)
if_not_exists(LineItems, :empty) restituisce la lista corrente se presente,
altrimenti il fallback :empty (una lista vuota []). Ciò fa sì che la prima
aggiunta e ogni aggiunta successiva usino la stessa espressione — una vera ragione
per cui questi idiomi esistono.
ADD — incrementa il conteggio, atomicamente
Per incrementare ItemCount, non leggerlo, aggiungere uno nel tuo codice e
fare SET per riscriverlo. È una gara di update persi: due aggiunte concorrenti
leggono entrambe 3, scrivono entrambe 4, e ne hai persa una. ADD fa
l'aritmetica lato server:
ADD ItemCount :one
Con :one = 1, questo è un contatore atomico. Le chiamate concorrenti si
serializzano sull'item, così due aggiunte atterrano come +2. Passa un numero
negativo per decrementare. Se ItemCount è assente, ADD lo tratta come 0
prima — così non devi mai inizializzare il contatore.
Puoi costruire questa espressione esatta — nomi, valori tipizzati e la richiesta
marshalled — nel DynamoDB expression builder
senza fare l'escape a mano di un singolo placeholder #name o :value.
REMOVE — elimina un attributo o un line item
REMOVE è il modo in cui elimini del tutto un attributo (non c'è un "impostalo a
null" — quello scrive solo un tipo NULL). Azzera uno sconto applicato e togli il
terzo line item in una sola chiamata:
REMOVE AppliedDiscount, LineItems[2]
LineItems[2] rimuove l'elemento all'indice 2 e fa scorrere tutto ciò che lo
segue verso il basso — l'indice 3 diventa 2, e così via. Se fai REMOVE di due
indici in un'espressione, entrambi sono valutati contro la lista originale,
quindi rimuovere [2] e [3] insieme toglie il terzo e il quarto elemento come
ti aspetteresti.
DELETE — rimuovi membri da un set
PromoCodes è un set di stringhe, quindi un cliente che toglie un codice usa
DELETE, non REMOVE. REMOVE PromoCodes annienterebbe l'intero set; DELETE
sottrae i membri nominati:
DELETE PromoCodes :pulled
Con :pulled = il set {"SAVE10"}, va via solo quel membro. Due regole mordono
qui: un set non può mai essere vuoto, quindi eliminare l'ultimo membro rimuove del
tutto l'attributo PromoCodes; e il valore deve essere di tipo set corrispondente
all'attributo — una stringa nuda è un errore di tipo.
Mettila insieme
Un update "aggiungi item, applica un promo, incrementa il conteggio" è una sola chiamata attraverso tre clausole:
SET LineItems = list_append(if_not_exists(LineItems, :empty), :newItem),
OrderTotal = OrderTotal + :price
ADD ItemCount :one
DELETE PromoCodes :expiredCode
Nota OrderTotal = OrderTotal + :price — l'aritmetica dentro SET opera sul
valore esistente. Non è atomica come lo è ADD per la sicurezza dalle gare, ma
legge il totale corrente lato server invece di farlo passare per il tuo codice.
Trappole da evitare
- Fare
SETsu un contatore che leggi prima. UsaADD— il read-modify-write perde update sotto concorrenza. È il bug più comune di carrello/inventario. list_appendsu una lista mancante. Avvolgi il target inif_not_existso la prima scrittura fallisce.- Confondere
REMOVEeDELETE.REMOVEtoglie l'attributo;DELETEsottrae membri da un set. Mescolarli elimina più di quanto intendevi. - Dimenticare che
UpdateItemè un upsert. Se la chiave non esiste, crea l'item. Usa unaConditionExpression(attribute_exists(CartPK)) quando intendi "aggiorna solo".
Per modellare le chiavi contro cui girano queste espressioni, vedi single-table design; per decidere come leggerai indietro il carrello, vedi query vs scan.
Costruisci e copia una qualsiasi di queste nell'expression builder, poi prova DynoTable per eseguirle contro le tue tabelle e guardare l'item cambiare dal vivo.