Fortgeschritten5 Min. Lesezeit

DynamoDB Update Expressions: SET, REMOVE, ADD, DELETE (mit Beispielen)

Eine Update Expression sagt UpdateItem, wie ein einzelnes Item verändert werden soll: welche geschrieben, erhöht, gelöscht oder in ein Set gefaltet werden. Es gibt kein UPDATE … SET … WHERE über mehrere Zeilen — du benennst ein einzelnes Item über seinen vollständigen Key und beschreibst die Änderung mit vier Klausel-Keywords.

Wie funktionieren DynamoDB Update Expressions?

Eine DynamoDB Update Expression sagt UpdateItem über vier Klauseln, wie ein Item verändert werden soll. SET schreibt oder überschreibt ein . ADD erhöht atomar eine Zahl oder vereinigt in ein Set. REMOVE löscht ein Attribut oder ein einzelnes Listenelement. DELETE entfernt bestimmte Mitglieder aus einem Set. Ein Aufruf kann alle vier gleichzeitig tragen.

  • SET schreibt oder überschreibt ein Attribut — Skalare, Dokumente und die Funktions-Idiome if_not_exists und list_append.
  • ADD erhöht eine Zahl atomar oder vereinigt in ein Set, in einem Round Trip, ohne vorheriges Lesen.
  • REMOVE löscht ein Attribut komplett (oder ein einzelnes Listenelement über seinen Index).
  • DELETE entfernt bestimmte Mitglieder aus einem Set — und nur aus einem Set.

Aus der SQL-Welt ist die Falle, für alles zu SET zu greifen. ADD und DELETE existieren, weil Read-Modify-Write auf einem Zähler oder einem Set ein Race ist, das du unter Nebenläufigkeit verlierst.

Wähle die Klausel danach, was du änderst

Ein UpdateItem-Aufruf kann alle vier Klauseln gleichzeitig tragen, in beliebiger Reihenfolge. Jedes Keyword taucht höchstens einmal auf und nimmt eine kommagetrennte Liste von Aktionen entgegen.

KlauselWirkt aufNimm sie, um
SETJedes Attributeinen Wert oder ein Dokumentfeld zu schreiben/überschreiben
ADDNur Zahl oder Setatomar zu erhöhen oder in ein Set zu vereinigen
REMOVEJedes Attribut oder Listenelementein Attribut zu löschen; einen Listenindex zu entfernen
DELETENur Setbestimmte Mitglieder aus einem Set zu entfernen

ADD auf einem String und DELETE auf einem Skalar sind Validierungsfehler, keine No-Ops — DynamoDB lehnt den ganzen Aufruf ab. Laut der AWS-Referenz zu Update Expressions ist ADD auf Zahlen und Sets beschränkt und DELETE auf Sets.

Das durchgerechnete Beispiel: ein Warenkorb

Ein Item pro Warenkorb, gekeyt über CartPK = "CART#c-9f21" und CartSK = "SUMMARY". Es führt eine laufende OrderTotal, eine Liste LineItems, ein String-Set PromoCodes und ein ItemCount.

SET — die Skalare und Dokumente schreiben

SET überschreibt, was auch immer da war. Füge im selben Aufruf eine Position zur Liste hinzu und erhöhe die Summe:

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

list_append(LineItems, :newItem) hängt hinten an; dreh die Argumente um — list_append(:newItem, LineItems) —, um vorn anzuhängen. Die Reihenfolge der Argumente ist die Reihenfolge der Verkettung, mehr nicht.

In diesem ersten Aufruf steckt ein Footgun: Ist der Warenkorb brandneu, existiert LineItems noch nicht, und list_append auf einem fehlenden Attribut schlägt fehl. Sichere das mit if_not_exists ab:

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

if_not_exists(LineItems, :empty) gibt die aktuelle Liste zurück, wenn sie existiert, sonst den Rückfallwert :empty (eine leere Liste []). Damit nutzen der erste und jeder weitere Hinzufügen-Vorgang denselben Ausdruck — ein echter Grund, warum es diese Idiome gibt.

ADD — die Anzahl atomar erhöhen

Um ItemCount zu erhöhen, lies ihn nicht aus, addier eins in deinem Code und schreib ihn per SET zurück. Das ist ein Lost-Update-Race: Zwei nebenläufige Additionen lesen beide 3, schreiben beide 4, und du hast eine verloren. ADD rechnet serverseitig:

ADD ItemCount :one

Mit :one = 1 ist das ein atomarer Zähler. Nebenläufige Aufrufe serialisieren auf dem Item, zwei Additionen landen also als +2. Übergib eine negative Zahl, um zu verringern. Fehlt ItemCount, behandelt ADD ihn zuerst als 0 — du musst den Zähler also nie vorbelegen.

Bei On-Demand in us-east-1 berechnet jedes ADD 1 WCU pro KB des Items nach dem Schreibvorgang (aufgerundet). Eine 1 KB große Warenkorb-Zusammenfassung mit einem ADD ItemCount :one kostet 1 WCU — dieselbe Zeile mit einem Read-Modify-Write per SET würde dieselben WCU kosten, aber unter Nebenläufigkeit verlieren. Dimensioniere das Item im Item-Size-Rechner.

Genau diesen Ausdruck — Namen, typisierte Werte und den gemarshallten Request — kannst du im DynamoDB Expression Builder bauen, ohne einen einzigen #name- oder :value-Platzhalter von Hand zu escapen.

Bearbeite das Preset unten — ein SET plus ein atomares ADD — und sieh zu, wie sich die UpdateExpression dabei neu aufbaut:

Erstelle deine Anfrage
Generierter Code
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 — ein Attribut oder eine Position entfernen

REMOVE ist der Weg, ein Attribut vollständig zu löschen (ein „setz es auf null“ gibt es nicht — das schreibt nur einen Typ NULL). Entferne einen angewendeten Rabatt und die dritte Position in einem Aufruf:

REMOVE AppliedDiscount, LineItems[2]

LineItems[2] entfernt das Element an Index 2 und schiebt alles danach nach unten — Index 3 wird zu 2 und so weiter. Entfernst du zwei Indizes in einem Ausdruck, werden beide gegen die ursprüngliche Liste ausgewertet: [2] und [3] gemeinsam zu entfernen streicht also, wie erwartet, das dritte und vierte Element.

DELETE — Set-Mitglieder entfernen

PromoCodes ist ein String-Set, ein Kunde, der einen Code zurückzieht, nutzt also DELETE, nicht REMOVE. REMOVE PromoCodes würde das ganze Set plattmachen; DELETE zieht die genannten Mitglieder ab:

DELETE PromoCodes :pulled

Mit :pulled = dem Set {"SAVE10"} verschwindet nur dieses Mitglied. Zwei Regeln beißen hier: Ein Set darf nie leer sein, das Löschen des letzten Mitglieds entfernt also das Attribut PromoCodes ganz; und der Wert muss ein Set-Typ sein, der zum Attribut passt — ein nackter String ist ein Typfehler.

Alles zusammensetzen

Ein Update im Sinne von „Position hinzufügen, Promo anwenden, Anzahl erhöhen“ ist ein Aufruf über drei Klauseln:

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

Beachte OrderTotal = OrderTotal + :price — Arithmetik innerhalb von SET arbeitet auf dem bestehenden Wert. Sie ist genauso atomar und race-sicher wie ADD: DynamoDB wertet OrderTotal + :price serverseitig gegen den aktuellen Wert aus, nebenläufige Aufrufe serialisieren also auf dem Item, statt einen Umweg durch deinen Code zu nehmen.

Fallstricke, die du vermeiden solltest

  • Einen Zähler per SET schreiben, den du vorher gelesen hast. Nimm ADD — Read-Modify-Write verliert Updates unter Nebenläufigkeit. Das ist der häufigste Warenkorb-/Bestandsfehler.
  • list_append auf einer fehlenden Liste. Wickle das Ziel in if_not_exists, sonst schlägt der erste Schreibvorgang fehl.
  • REMOVE und DELETE verwechseln. REMOVE entfernt das Attribut; DELETE zieht Mitglieder aus einem Set ab. Sie zu vermischen löscht mehr, als du wolltest.
  • Vergessen, dass UpdateItem ein Upsert ist. Existiert der Key nicht, legt es das Item an. Nimm eine ConditionExpression (attribute_exists(CartPK)), wenn du „nur aktualisieren“ meinst.

Zum Modellieren der Keys, gegen die diese Ausdrücke laufen, siehe Single-Table-Design; um zu entscheiden, wie du den Warenkorb zurücklesen willst, siehe Query vs. Scan.

Baue und kopiere alle diese Ausdrücke im Expression Builder und probier dann DynoTable aus, um sie gegen deine eigenen Tabellen laufen zu lassen und dem Item live beim Ändern zuzusehen.

Aktualisiert