DynamoDB UpdateItem in Python (boto3)

boto3 ti dà due client per questa chiamata e i due non sono d'accordo su cosa sia un numero. Il client di basso livello qui sotto invia e riceve JSON DynamoDB, dove ogni numero è una stringa fra virgolette. resource("dynamodb").Table(...) accetta oggetti Python nativi, rifiuta di netto float e restituisce i numeri come decimal.Decimal. Sceglierne uno è la vera decisione di questa pagina.

Codice

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

Spiegazione

  • La grammatica delle clausole non è affar suo di boto3. L'UpdateExpression è una stringa opaca che si limita a inoltrare; solo DynamoDB la analizza, quindi gli errori costano un round trip. ADD qui è l'incremento atomico che elimina la corsa read-modify-write, attribute_exists(Artist) in una ConditionExpression trasforma l'upsert in un solo update, e il resto sta in update expression.
  • La risposta ha esattamente due chiavi di primo livello: Attributes e ResponseMetadata. Non c'è alcun campo di stato da controllare né un conteggio di righe. Se la chiamata è tornata, ha funzionato; ResponseMetadata porta il RequestId e l'HTTPStatusCode che vuoi in una riga di log.
  • ReturnValues="UPDATED_NEW" è l'opzione parsimoniosa. Restituisce solo gli attributi toccati dall'espressione, il che su un Item grande è la differenza fra leggere un contatore e rispedire indietro l'intero record.
  • Gli errori arrivano come botocore.exceptions.ClientError, e ramifichi su e.response["Error"]["Code"]. Un alias mancante produce ValidationException con il messaggio Invalid UpdateExpression: Attribute name is a reserved keyword; reserved keyword: Year. Le sottoclassi tipizzate esistono, ma solo come attributi che botocore genera sull'istanza del client (client.exceptions.ConditionalCheckFailedException), mai come simboli importabili, quindi una funzione helper che non ha il client nello scope deve usare la stringa del codice.

Decimal o JSON DynamoDB, scegline uno

L'API resource rifiuta float prima ancora che la richiesta sia costruita, con un messaggio che ti dice esattamente cosa vuole:

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

È il controllo di tipo di boto3, non di DynamoDB. Memorizza Decimal("4.5") attraverso l'API resource e rileggi lo stesso attributo attraverso entrambi i client, e ottieni:

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

Nessuno dei due è sbagliato; sono contratti diversi. Decimal mantiene la precisione che DynamoDB memorizza davvero e ti obbliga a ragionare sull'aritmetica, al prezzo di un Decimal("1") * 2 che spunta in codice che si aspettava un int. Il client di basso livello ti passa stringhe e lascia a te il parsing, che è quello che fa lo snippet qui sopra.

La regola che ne deriva: non mescolarli nello stesso percorso di codice. Un Item scritto attraverso Table.put_item e letto attraverso client.get_item torna indietro in una forma diversa, e il bug salta fuori nel ramo che hai testato meno.

Una nota sugli attributi TTL

Il SET numerico più comune in un codebase Python è un TTL: SET expires_at = :t con un epoch Unix. DynamoDB legge quell'attributo in secondi. Scrivi invece int(time.time() * 1000) e il valore è 1785269450912, che letto come secondi finisce nell'anno 58542, quindi l'Item non viene mai eliminato e nessuno protesta. Il convertitore TTL DynamoDB rilegge un epoch in entrambe le unità e ti dice quale hai scritto. Per rileggere poi il valore memorizzato da una tabella reale, scarica DynoTable.

Guide correlate

Riferimenti

Ultima verifica 2026-07-28 rispetto alla documentazione ufficiale AWS collegata sopra.

Lavora con DynamoDB senza la Console

Un client desktop veloce per DynamoDB che esegue il vero SQL che DynamoDB non può — JOINs, GROUP BY, aggregazioni — con modifica visuale e un agente AI sulle tue chiavi Bedrock.

Prova gratuita di 30 giorni, senza carta di credito — poi il piano Free senza limiti di tempo.