DynamoDB GetItem en Python (boto3)

get_item récupère un élément par sa clé primaire complète. Le client bas niveau de boto3 (boto3.client("dynamodb")) parle le JSON DynamoDB dans les deux sens : la clé part donc emballée avec son type et l'élément revient de la même façon. Ce qui le distingue de query et scan est traité dans les actions par élément.

Code

import boto3

client = boto3.client("dynamodb")

response = client.get_item(
    TableName="Music",
    Key={"Artist": {"S": "Arturo Sandoval"}, "SongTitle": {"S": "Cubano Chant"}},
    ProjectionExpression="#proj0, #proj1, #proj2, #proj3",
    ExpressionAttributeNames={"#proj0": "Artist", "#proj1": "SongTitle", "#proj2": "AlbumTitle", "#proj3": "Year"},
)

item = response.get("Item")
if item is None:
    print("Item not found")
else:
    print(item)

Explication

Un échec de correspondance renvoie une réponse sans aucune clé Item. Ni None, ni un dict vide. En lisant la même table pour une clé qui n'existe pas, les clés de premier niveau de la réponse étaient exactement :

['ResponseMetadata']

C'est pour ça que le snippet utilise response.get("Item"). response["Item"] lève un KeyError sur le chemin ordinaire du « non trouvé », et c'est comme ça qu'une ligne manquante se transforme en 500 dans un handler web. La lecture t'est facturée quand même : la page d'AWS sur la capacité de lecture indique que "if you perform a read operation on an item that doesn't exist, DynamoDB will still consume read throughput as outlined above" (consultée le 2026-07-28).

Year est un mot réservé, et c'est pour ça que le snippet généré aliase chaque attribut projeté. Supprime les alias #proj et passe ProjectionExpression="Year", et le moteur rejette la lecture :

ValidationException: Invalid ProjectionExpression: Attribute name is a reserved keyword; reserved keyword: Year

Aliaser systématiquement ne coûte rien et supprime toute cette classe d'échecs. La liste complète compte 573 mots ; voir "Attribute name is a reserved keyword".

Quatre façons de se tromper de Key, trois messages différents. Ils valent la peine d'être distingués, parce qu'aucun n'est l'erreur « provided key element does not match the schema » à laquelle on s'attend. Reproduit sur une table Music clé sur Artist (partition) + SongTitle (tri) :

Ce que tu as passéMessage ValidationException verbatim
{"Artist": …} — clé de tri manquanteThe number of conditions on the keys is invalid
{"Artist": …, "SongTitle": …, "Extra": …}The number of conditions on the keys is invalid
{"Artist": …, "Song": …} — mauvais nom d'attributOne of the required keys was not given a value
{"Artist": {"N": "1"}, …} — mauvais typeOne or more parameter values were invalid: Type mismatch for key

Remarque qu'un attribut de clé manquant et un attribut en trop produisent le même message : « number of conditions » veut donc dire « tu ne m'as pas donné exactement le schéma de clé », et non « tu en as passé trop peu ».

ProjectionExpression réduit la charge utile, pas la facture. En lisant un élément d'environ 15 KB de trois façons avec ReturnConsumedCapacity="TOTAL" :

full item, eventually consistent          CapacityUnits: 2.0
ProjectionExpression="#y" (Year only)     CapacityUnits: 2.0
ProjectionExpression="#y" + ConsistentRead  CapacityUnits: 4.0

La projection a fait passer la réponse d'environ 15 KB à un seul nombre, et n'a rien changé au coût. AWS le dit clairement : "The number of capacity units consumed will be the same whether you request all of the attributes (the default behavior) or just some of them (using a projection expression)" (Query API Reference, consultée le 2026-07-28). ConsistentRead=True est le seul paramètre de cette liste qui fasse bouger le chiffre, et il le double. Voir les expressions de projection pour ce à quoi servent réellement les projections.

L'API resource est un contrat différent, pas une écriture plus jolie. boto3.resource("dynamodb").Table("Music").get_item(...) renvoie du Python ordinaire et chaque nombre en decimal.Decimal :

{'Artist': 'Arturo Sandoval', 'AlbumTitle': 'Danzon', 'Awards': Decimal('0'), 'Year': Decimal('1994'), 'SongTitle': 'Cubano Chant'}

Ça coupe dans les deux sens. Réécrire via la même API avec un float lève avant même que la requête ne quitte ta machine :

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

Si celle-là te mord, "Float types are not supported" a le correctif. Mélanger les deux API dans une même base de code est le vrai piège : le client bas niveau acceptera volontiers un {"N": "1.5"} que l'API resource aurait rejeté.

Les erreurs arrivent sous forme d'exceptions botocore, et boto3 leur donne de vraies classes. Sur la 1.43.58, l'objet levé pour une condition échouée est ConditionalCheckFailedException, une sous-classe de ClientError : except ClientError plus un contrôle sur err.response["Error"]["Code"] et except client.exceptions.ConditionalCheckFailedException fonctionnent donc tous les deux. Choisis celui que ta base de code utilise déjà ; ne fais pas de correspondance sur str(e).

Le faire visuellement

Avant d'aliaser à la main : le vérificateur de mots réservés DynamoDB gratuit prend tes noms d'attributs, te dit lesquels des 573 mots réservés tu touches, et produit la map ExpressionAttributeNames prête à coller.

Pour parcourir des tables et exécuter GetItem sur tes propres données — formulaire de clé, grille de résultats, requête recopiée en boto3 — télécharge DynoTable.

Guides liés

Références

Reproduit le 2026-07-28 sur DynamoDB Local (amazon/dynamodb-local) sur le port 9000 avec boto3 1.43.58 / botocore 1.43.58. Chaque message et chaque chiffre de capacité ci-dessus sont la sortie du moteur, copiés tels quels. DynamoDB Local n'est pas le service ; là où l'on sait que les deux formulent une erreur différemment, on le signale sur la page d'erreur.

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.