DynamoDB UpdateItem en Python (boto3)

boto3 te donne deux clients pour cet appel, et ils ne sont pas d'accord sur ce qu'est un nombre. Le client bas niveau ci-dessous envoie et reçoit du JSON DynamoDB, où chaque nombre est une chaîne entre guillemets. resource("dynamodb").Table(...) prend des objets Python natifs, refuse catégoriquement float, et rend les nombres en decimal.Decimal. Le vrai choix de cette page, c'est de trancher entre les deux.

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

Explication

  • La grammaire des clauses ne regarde pas boto3. L'UpdateExpression est une chaîne opaque qu'il transmet ; seul DynamoDB l'analyse, et les erreurs coûtent donc un aller-retour. ADD est ici l'incrément atomique qui supprime la course lecture-modification-écriture, attribute_exists(Artist) dans une ConditionExpression transforme l'upsert en mise à jour seule, et le reste est dans les expressions de mise à jour.
  • La réponse a exactement deux clés de premier niveau : Attributes et ResponseMetadata. Il n'y a aucun champ de statut à vérifier ni aucun nombre de lignes. Si l'appel a retourné, c'est que ça a marché ; ResponseMetadata porte le RequestId et le HTTPStatusCode que tu veux dans une ligne de log.
  • ReturnValues="UPDATED_NEW" est l'option économe. Elle ne renvoie que les attributs que l'expression a touchés, ce qui, sur un gros élément, fait la différence entre relire un compteur et rapatrier tout l'enregistrement.
  • Les erreurs arrivent sous forme de botocore.exceptions.ClientError, et tu branches sur e.response["Error"]["Code"]. Un alias manquant produit une ValidationException avec le message Invalid UpdateExpression: Attribute name is a reserved keyword; reserved keyword: Year. Les sous-classes typées existent bien, mais uniquement comme attributs que botocore génère sur l'instance du client (client.exceptions.ConditionalCheckFailedException), jamais comme symboles importables : une fonction utilitaire qui n'a pas le client sous la main doit donc utiliser la chaîne du code.

Decimal ou JSON DynamoDB, il faut choisir

L'API resource rejette float avant même que la requête ne soit construite, avec un message qui dit exactement ce qu'elle veut :

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

C'est le typage de boto3 lui-même, pas celui de DynamoDB. Stocke Decimal("4.5") via l'API resource, relis le même attribut avec les deux clients, et tu obtiens :

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

Aucun des deux n'a tort ; ce sont des contrats différents. Decimal conserve la précision que DynamoDB stocke réellement et t'oblige à réfléchir à l'arithmétique, au prix d'un Decimal("1") * 2 qui surgit dans du code qui attendait un int. Le client bas niveau te rend des chaînes et te laisse l'analyse, ce que fait le snippet ci-dessus.

La règle qui en découle : ne les mélange pas dans un même chemin de code. Un élément écrit via Table.put_item et lu via client.get_item revient sous une forme différente, et le bug apparaît dans la branche que tu as le moins testée.

Une note sur les attributs TTL

Le SET numérique le plus courant dans une base de code Python, c'est un TTL : SET expires_at = :t avec un timestamp Unix. DynamoDB lit cet attribut en secondes. Écris int(time.time() * 1000) à la place et la valeur vaut 1785269450912, ce qui, en secondes, tombe en l'an 58542 : l'élément n'est donc jamais supprimé et personne ne se plaint. Le convertisseur TTL DynamoDB relit un timestamp dans les deux unités et te dit laquelle tu as écrite. Pour relire ensuite la valeur stockée depuis une vraie table, télécharge DynoTable.

Guides liés

Références

Dernière vérification le 2026-07-28 par rapport à la documentation officielle AWS liée ci-dessus.

Travaille avec DynamoDB sans la Console

Un client de bureau rapide pour DynamoDB qui exécute le vrai SQL que DynamoDB ne peut pas — JOINs, GROUP BY, agrégations — avec édition visuelle et un agent IA sur tes propres clés Bedrock.

Essai gratuit de 30 jours, sans carte bancaire — ensuite la formule Gratuit, sans limite de durée.