Fortgeschritten5 Min. Lesezeit

DynamoDB ReturnValues: das alte oder neue Item bekommen

Standardmäßig gibt ein DynamoDB-Schreibvorgang nichts außer Erfolg zurück. Oft brauchst du aber die Daten rund um den Schreibvorgang — den Wert vor deiner Änderung oder den frischen Wert danach. Die naive Lösung ist ein zweites GetItem, und das ist ein zusätzlicher Round Trip und ein Race: Jemand anderes kann dazwischen schreiben. DynamoDB vermeidet beides mit dem Parameter ReturnValues, der dir das alte oder neue Item atomar als Teil des Schreibvorgangs selbst zurückgibt.

Was macht ReturnValues in DynamoDB?

ReturnValues weist einen DynamoDB-Schreibvorgang an, das Item als Teil desselben Aufrufs zurückzugeben, sodass du ein zweites GetItem und das dadurch entstehende Race sparst. PutItem und DeleteItem akzeptieren NONE oder ALL_OLD; UpdateItem akzeptiert alle fünf (NONE, ALL_OLD, UPDATED_OLD, ALL_NEW, UPDATED_NEW) und gibt alte oder neue Werte atomar zurück.

  • ReturnValues gibt das Item als Teil des Schreibvorgangs zurück — kein zweiter Lesevorgang, kein Race.
  • NONE (Standard) — gibt nichts zurück.
  • ALL_OLD — das gesamte Item, so wie es vor dem Schreibvorgang war.
  • UPDATED_OLD — nur die vom Update geänderten Attribute, mit den Werten davor.
  • ALL_NEW — das gesamte Item nach dem Schreibvorgang.
  • UPDATED_NEW — nur die geänderten Attribute, mit den Werten danach.
  • PutItem/DeleteItem akzeptieren nur NONE oder ALL_OLD; UpdateItem akzeptiert alle fünf.

Das Problem: du brauchst den Wert, den du gerade überschrieben hast

Angenommen, du betreibst einen Support-Desk und eine Agentin ändert den Status eines Tickets von open auf pending. Dein Audit-Log muss festhalten, welchen Status es vorher hatte. Ohne ReturnValues würdest du:

  1. GetItem, um den aktuellen Status zu lesen,
  2. UpdateItem, um den neuen zu setzen.

Zwischen Schritt 1 und 2 könnte ein anderer Agent den Status ändern — jetzt hält dein Audit-Log einen veralteten „Vorher“-Wert fest. Schlimmer noch: Es sind zwei Aufrufe für eine logische Operation. ReturnValues faltet das in ein einziges atomares UpdateItem, das den alten Status so zurückgibt, wie er zum Zeitpunkt des Schreibens tatsächlich war.

Die fünf Optionen und wann du welche nimmst

UpdateItem unterstützt den vollen Satz; die Wahl hängt davon ab, welchen Ausschnitt des Items und welche Seite des Schreibvorgangs du brauchst:

ReturnValuesGibt zurückNimm es, wenn
NONEnichtsdu das Item nicht zurückbrauchst (Standard)
ALL_OLDganzes Item, vor dem SchreibenAuditing / „was habe ich gerade ersetzt?“
UPDATED_OLDgeänderte Attribute, vor dem Schreibendich nur die Felder interessieren, die du angefasst hast
ALL_NEWganzes Item, nach dem Schreibendu das frische vollständige Item an einen Aufrufer zurückgeben musst
UPDATED_NEWgeänderte Attribute, nach dem Schreibendu einen gerade erhöhten Zähler/Wert zurücklesen willst

UPDATED_NEW ist der Alltagsheld: Erhöhe einen Zähler mit einer Update Expression und lies die neue Summe im selben Aufruf zurück, ohne Race. Für das Support-Ticket-Audit hält ALL_OLD (oder UPDATED_OLD, wenn du nur das Statusfeld loggst) den Zustand vor der Änderung atomar fest.

Beachte die Asymmetrie: PutItem und DeleteItem unterstützen nur NONE und ALL_OLD — bei einem Delete gibt es keinen „neuen“ Wert zurückzugeben, und der neue Wert eines Put ist genau das, was du geschickt hast. Nur UpdateItem, das in-place verändert, bietet alle fünf. AWS dokumentiert die exakte Matrix.

Das Update in DynoTable schreiben

Setze das UpdateItem und seine Update Expression visuell mit dem DynamoDB Expression Builder zusammen — er gibt die SET/ADD-Klausel plus die Attributnamen- und Wert-Maps aus. In der App zeigt DynoTable das resultierende Item, nachdem ein gestagter Schreibvorgang committet wurde, sodass du den neuen Zustand direkt siehst.

Die gestagte Änderung eines Items in DynoTable prüfen — alte und neue Werte, bevor das Update committet wird.
Die gestagte Änderung eines Items in DynoTable prüfen — alte und neue Werte, bevor das Update committet wird.

Fallstricke + nächste Schritte

  • Kein GetItem-dann-Schreiben, um rund um eine Änderung zu lesen — das ist ein Round Trip und ein Race; nimm ReturnValues.
  • UPDATED_* gibt nur die angefassten Attribute zurück — brauchst du das ganze Item, nimm ALL_*.
  • PutItem/DeleteItem können keine neuen Werte zurückgeben — nur NONE/ALL_OLD.
  • ReturnValues ersetzt keine Bedingung — um einen Schreibvorgang zu schützen, ergänze eine Condition Expression; um seine Wirkung zurückzulesen, nimm ReturnValues. Beides lässt sich kombinieren.
  • Verwandt: Update Expressions, atomare Zähler.

Du willst Änderungen machen und Vorher/Nachher sehen, ohne zwei Aufrufe zu skripten? Lade DynoTable herunter und bearbeite deine Items direkt.

Atomarer Zähler mit UPDATED_NEW

Bestandssysteme erhöhen bei jedem Schreibvorgang ein Feld version oder stock. Das Muster ist ein UpdateItem mit ADD stock :inc und ReturnValues: UPDATED_NEW:

UpdateItem  PK=SKU#8842
  UpdateExpression: ADD stock :one
  ExpressionAttributeValues: {":one": {"N": "1"}}
  ReturnValues: UPDATED_NEW
Attributes.stock.N == "41"   (was 40)

Du erhältst nur die Map der geänderten Attribute, nicht das ganze Item — ideal, wenn das Item groß ist, der Aufrufer aber nur den neuen Zähler braucht. Für Audit-Trails, die jedes Feld vor der Änderung festhalten müssen, wechsle auf ALL_OLD.

Der Schreibvorgang wird weiterhin als UpdateItem auf Basis der Item-Größe abgerechnet; ReturnValues erzeugt keine separate Lesegebühr — DynamoDB hat das Item ohnehin geladen, um das Update anzuwenden.

Hinweis zur Kapazität

Attribute zurückzugeben verdoppelt die WCU-Kosten des Schreibvorgangs nicht. Du zahlst für den Schreibvorgang gemäß den AWS-Regeln auf Basis der Item-Größe vor und nach dem Update, unabhängig davon, wie viele Attribute in der Response auftauchen.

Wärst du versucht gewesen, erst GetItem und dann UpdateItem aufzurufen, um den alten Wert zu loggen, hättest du einen Lese- plus einen Schreibvorgang bezahlt. ReturnValues: ALL_OLD am Update entfernt den Lesevorgang vollständig — bei einem 2-KB-Item und 500 Updates pro Sekunde spart das rund 250 letztendlich konsistente RCU pro Sekunde.

Mit Condition Expressions kombinieren

ReturnValues und Condition Expressions lassen sich im selben Aufruf kombinieren. Beispiel: retryCount nur erhöhen, solange er unter einer Obergrenze liegt, und den neuen Stand zurückgeben:

ConditionExpression: retryCount < :max
UpdateExpression: ADD retryCount :one
ReturnValues: UPDATED_NEW

Scheitert die Bedingung, gibt DynamoDB eine ConditionalCheckFailedException und kein Attribut-Payload zurück — zu unterscheiden von einem erfolgreichen Update mit leerem UPDATED_NEW, wenn sich nichts geändert hat.

Nutze den Expression Builder, um die UpdateExpression, die Bedingung und die gemarshallten Wert-Maps gemeinsam zu erzeugen.

Entscheidungshilfe

Du brauchst …EinstellungFunktioniert bei
Nichts zurückNONEPut, Update, Delete
Ganzes Item vor Überschreiben/LöschenALL_OLDPut, Update, Delete
Nur geänderte Felder, davorUPDATED_OLDUpdate
Ganzes Item nach dem PatchALL_NEWUpdate
Nur geänderte Felder, danachUPDATED_NEWUpdate

Deletes und Puts

DeleteItem mit ReturnValues: ALL_OLD ist der Weg, „Pop and Return“-Semantik auf einem Queue-Item umzusetzen — die gelöschte Zeile kommt in Attributes zurück. Es gibt kein ALL_NEW beim Delete, weil das Item danach nicht mehr existiert.

PutItem mit ALL_OLD gibt das vorherige Item zurück, wenn du einen bestehenden Key überschreibst — nützlich für Swap-Abläufe. Existierte der Key nicht, lässt die Response Attributes weg.

In DynoTable nachprüfen

Stage eine Attributänderung im Item-Editor: Der Review-Bereich zeigt alte und neue Werte vor dem Commit nebeneinander — dieselbe Information, die UPDATED_OLD und UPDATED_NEW zurückgeben würden, ganz ohne Skript. Nach dem Commit kopierst du die Zeile über die Export-Aktionen des Grids als JSON für Testfixtures.

Aktualisiert