DynamoDB UpdateItem in Python (boto3)

boto3 gibt dir für diesen Aufruf zwei Clients, und sie sind sich uneinig darüber, was eine Zahl ist. Der Low-Level-client unten sendet und empfängt DynamoDB JSON, wo jede Zahl ein String in Anführungszeichen ist. resource("dynamodb").Table(...) nimmt native Python-Objekte, verweigert float rundheraus und gibt Zahlen als decimal.Decimal zurück. Sich für einen zu entscheiden ist die eigentliche Entscheidung auf dieser Seite.

Code

import boto3

client = boto3.client("dynamodb")

response = client.update_item(
    TableName="Music",
    Key={"Artist": {"S": "Arturo Sandoval"}, "SongTitle": {"S": "Cubano Chant"}},
    UpdateExpression="SET #upd0 = :updValue0, #upd1 = :updValue1 ADD #upd2 :updValue2",
    ExpressionAttributeNames={"#upd0": "Genre", "#upd1": "Year", "#upd2": "Awards"},
    ExpressionAttributeValues={":updValue0": {"S": "Latin Jazz"}, ":updValue1": {"N": "1994"}, ":updValue2": {"N": "1"}},
    ReturnValues="ALL_NEW",
)

print(response["Attributes"])  # the item after the update

Erklärung

  • Die Klausel-Grammatik geht boto3 nichts an. Die UpdateExpression ist ein opaker String, den es weiterreicht; nur DynamoDB parst sie, Fehler kosten also einen Round-Trip. ADD ist hier das atomare Inkrement, das die Read-Modify-Write-Race beseitigt, attribute_exists(Artist) in einer ConditionExpression macht aus dem Upsert ein reines Update, und der Rest steht in Update Expressions.
  • Die Antwort hat genau zwei Top-Level-Keys: Attributes und ResponseMetadata. Es gibt kein Statusfeld zu prüfen und keine Zeilenzahl. Wenn der Aufruf zurückkam, hat er funktioniert; ResponseMetadata trägt die RequestId und den HTTPStatusCode, die du in einer Log-Zeile haben willst.
  • ReturnValues="UPDATED_NEW" ist die sparsame Option. Es liefert nur die Attribute zurück, die die Expression angefasst hat — bei einem großen Item ist das der Unterschied zwischen einem gelesenen Zähler und dem gesamten Datensatz auf dem Rückweg.
  • Fehler kommen als botocore.exceptions.ClientError, und du verzweigst über e.response["Error"]["Code"]. Ein fehlender Alias erzeugt eine ValidationException mit der Meldung Invalid UpdateExpression: Attribute name is a reserved keyword; reserved keyword: Year. Die typisierten Unterklassen existieren zwar, aber nur als Attribute, die botocore auf der Client-Instanz erzeugt (client.exceptions.ConditionalCheckFailedException), nie als importierbare Symbole — eine Hilfsfunktion ohne Client im Scope muss also den Code-String verwenden.

Decimal oder DynamoDB JSON, entscheide dich

Die Resource-API lehnt float ab, bevor die Anfrage überhaupt gebaut wird, mit einer Meldung, die genau sagt, was sie will:

TypeError: Float types are not supported. Use Decimal types instead.

Das ist boto3s eigene Typprüfung, nicht die von DynamoDB. Speichere Decimal("4.5") über die Resource-API und lies dasselbe Attribut über beide Clients zurück, und du bekommst:

resource Rating: Decimal('4.5') Awards: Decimal('2')
client Rating: {'N': '4.5'} Awards: {'N': '2'}

Keines von beiden ist falsch; es sind verschiedene Verträge. Decimal behält die Präzision, die DynamoDB tatsächlich speichert, und zwingt dich, über Arithmetik nachzudenken — zum Preis, dass Decimal("1") * 2 in Code auftaucht, der ein int erwartet hat. Der Low-Level-Client gibt dir Strings und überlässt dir das Parsen, und genau das macht das Snippet oben.

Daraus folgt die Regel: Mische sie nicht in einem Codepfad. Ein über Table.put_item geschriebenes und über client.get_item gelesenes Item kommt in anderer Form zurück, und der Bug taucht in dem Zweig auf, den du weniger getestet hast.

Eine Anmerkung zu TTL-Attributen

Das häufigste numerische SET in einer Python-Codebasis ist ein TTL: SET expires_at = :t mit einem Unix-Epoch. DynamoDB liest dieses Attribut als Sekunden. Schreib stattdessen int(time.time() * 1000), und der Wert ist 1785269450912, was als Sekunden im Jahr 58542 landet — das Item wird also nie gelöscht und niemand beschwert sich. Der DynamoDB-TTL-Konverter liest einen Epoch-Wert in beiden Einheiten zurück und sagt dir, welche du geschrieben hast. Um den gespeicherten Wert danach aus einer echten Tabelle zurückzulesen, lade DynoTable herunter.

Verwandte Leitfäden

Referenzen

Zuletzt verifiziert am 2026-07-28 gegen die oben verlinkte offizielle AWS-Dokumentation.

Mit DynamoDB ohne die Console arbeiten

Ein schneller DynamoDB-Desktop-Client, der das echte SQL ausführt, das DynamoDB nicht kann — JOINs, GROUP BY, Aggregationen — mit visueller Bearbeitung und einem KI-Agenten auf deinen eigenen Bedrock-Schlüsseln.

30 Tage kostenlos testen, keine Kreditkarte — danach der Kostenlos-Tarif ohne Zeitlimit.