Python(boto3)での DynamoDB GetItem
get_item は 完全なプライマリキー で 1 件のアイテムを取得します。boto3 の 低レベルクライアント(boto3.client("dynamodb"))は双方向で DynamoDB JSON を話すので、キーは型で包んで渡し、アイテムも同じ形で返ってきます。query や scan との違いはアイテム単位の操作で扱っています。
コード
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)解説
ヒットしなかった場合、レスポンスには Item キーがそもそも含まれません。None でもなければ、空の dict でもありません。同じテーブルを、存在しないキーで読んだときのレスポンスのトップレベルキーは、ちょうどこれだけでした。
['ResponseMetadata']だからこのスニペットは response.get("Item") を使っています。response["Item"] は、ごく普通の「見つからない」経路で KeyError を送出します。これが、行が 1 つ無いだけで Web ハンドラーが 500 になる仕組みです。それでも読み取り分は課金されます。AWS の読み取りキャパシティのページには、"if you perform a read operation on an item that doesn't exist, DynamoDB will still consume read throughput as outlined above" と書かれています(2026-07-28 取得)。
Year は予約語です。生成されたスニペットが射影する属性すべてに別名を付けているのはそのためです。#proj の別名を外して ProjectionExpression="Year" を渡すと、エンジンは読み取りを拒否します。
ValidationException: Invalid ProjectionExpression: Attribute name is a reserved keyword; reserved keyword: Year無条件に別名を付けてもコストはゼロで、この種の失敗をまるごと取り除けます。リストの総数は 573 語です。"Attribute name is a reserved keyword"を参照してください。
Key を間違える 4 通りと、3 種類のメッセージ。どれも、人が予想する "provided key element does not match the schema" エラーではないので、見分けておく価値があります。Artist(パーティション)+ SongTitle(ソート)をキーとする Music テーブルに対して再現しました。
| 渡したもの | ValidationException メッセージ(逐語) |
|---|---|
{"Artist": …} — ソートキーが無い | The number of conditions on the keys is invalid |
{"Artist": …, "SongTitle": …, "Extra": …} | The number of conditions on the keys is invalid |
{"Artist": …, "Song": …} — 属性名が違う | One of the required keys was not given a value |
{"Artist": {"N": "1"}, …} — 型が違う | One or more parameter values were invalid: Type mismatch for key |
キー属性が 足りない 場合と 余分な 場合が同じメッセージになる点に注目してください。つまり「conditions の数」が意味しているのは「渡された数が少なすぎる」ではなく「キースキーマちょうどを渡さなかった」ということです。
ProjectionExpression が削るのはペイロードであって、請求ではありません。約 15 KB のアイテムを ReturnConsumedCapacity="TOTAL" 付きで 3 通りに読んだ結果です。
full item, eventually consistent CapacityUnits: 2.0
ProjectionExpression="#y" (Year only) CapacityUnits: 2.0
ProjectionExpression="#y" + ConsistentRead CapacityUnits: 4.0射影はレスポンスを約 15 KB から数値ひとつに変えましたが、コストは何も変えませんでした。AWS ははっきりこう述べています。"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、2026-07-28 取得)。そのリストの中で数値を動かす唯一のフラグが ConsistentRead=True で、これは 2 倍にします。射影が本来何のためのものかは射影式を参照してください。
リソース API は書き方がきれいになったものではなく、別の契約です。boto3.resource("dynamodb").Table("Music").get_item(...) は素の Python を返し、数値はすべて decimal.Decimal になります。
{'Artist': 'Arturo Sandoval', 'AlbumTitle': 'Danzon', 'Awards': Decimal('0'), 'Year': Decimal('1994'), 'SongTitle': 'Cubano Chant'}これは諸刃の剣です。同じ API を通して float で書き戻すと、リクエストがマシンを出る前に例外が上がります。
TypeError: Float types are not supported. Use Decimal types instead.これに刺さったら、"Float types are not supported"に対処法があります。本当の罠は、1 つのコードベースで 2 つの API を混ぜることです。低レベルクライアントは、リソース API なら拒否したはずの {"N": "1.5"} を平気で受け取ります。
エラーは botocore の例外として届き、boto3 はそれらに実クラスを与えています。1.43.58 では、条件が満たされなかったときに送出されるオブジェクトは ClientError のサブクラスである ConditionalCheckFailedException なので、except ClientError に err.response["Error"]["Code"] のチェックを添える方法も、except client.exceptions.ConditionalCheckFailedException も、どちらも機能します。コードベースで既に使っているほうを選んでください。str(e) でのマッチはやめましょう。
ビジュアルに行う
手作業で別名を付ける前に。無料の DynamoDB 予約語チェッカーは、属性名を渡すと 573 の予約語のどれに当たっているかを教え、そのまま貼り付けられる ExpressionAttributeNames のマップを出力します。
テーブルを参照して自分のデータに対して GetItem を実行するには — キーのフォーム、結果グリッド、リクエストの boto3 としてのコピー — DynoTable をダウンロードしてください。
関連ガイド
- Query と Scan の比較 — 1 回の
get_itemがqueryに勝る場面。 - DynamoDB のデータ型 — 各属性型が DynamoDB JSON でどう表現されるか。
- DynamoDB ResourceNotFoundException — ここで最初に出がちなエラー。テーブル名かリージョンの間違いです。
- "The provided key element does not match the schema" — 渡したキーがテーブルのキースキーマと一致していません。
参考資料
- GetItem — Amazon DynamoDB API Reference
- get_item — Boto3 DynamoDB.Client Reference
- Read consistency — Amazon DynamoDB Developer Guide
- Capacity unit consumption — Amazon DynamoDB Developer Guide
2026-07-28 に、DynamoDB Local(amazon/dynamodb-local)のポート 9000 に対し boto3 1.43.58 / botocore 1.43.58 で再現しました。上記のメッセージとキャパシティの数値はすべてエンジンの出力をそのまま逐語で写したものです。DynamoDB Local はサービス本体ではありません。両者で表現が異なると分かっているエラーについては、そのエラーページで明記しています。