こんにちは。ユウです。
Pythonを使ったDynamoDBの操作方法について知識の定着のため、まとめておきます。
バージョン
本記事のサンプルコードは以下のバージョンで動作することを確認しています。
項目 | バージョン |
Python | 3.12.3 |
boto3 | 1.34.124 |
botocore | 1.34.124 |
DynamoDBの主要コンポーネント
DyanamoDBの主要コンポーネントについて簡単に説明します(ドキュメント)。
コンポーネント | 説明 |
テーブル | ・データの集合 ・例:下記のPeopleテーブル |
項目 | ・テーブル内のレコード ・項目は1以上の属性で構成される ・テーブルの各項目は一意の識別子(プライマリーキー)を持つ ・例:Peopleテーブルの場合、各項目は人を表す。プライマリーキーはPersonID。 |
属性 | ・基盤となるデータ要素。属性は、それ以上分割できない。 ・例:Peopleテーブルの場合、属性はPersonID、LastName、FirstNameなど。 |
プライマリーキー
DynamoDBには以下の2種類のプライマリーキーがある。
- パーティションキー
- 1つの属性で構成されるシンプルなプライマリーキー。
- 例:上記のPersonテーブルのPersonID
- パーティションキーとソートキー
- 2つの属性で構成されるプライマリーキー。複合プライマリーキーとも呼ばれる。
- 2つの属性のうち最初の属性はパーティションキー。2番目の属性はソートキー。
- 複合プライマリーキーはクエリを実行するときの柔軟性を高める。パーティションキーのみ指定し、同一パーティションキーの全項目を取得するなど。
Boto3で使用する認証情報
Boto3で使用する認証情報の設定方法については以下があります(参考)。
- boto.client() メソッドにパラメーターで渡された資格情報
- Session オブジェクトの生成時にパラメーターで渡された資格情報
- 環境変数
- 共有された認証情報ファイル(~/.aws/credentials)
- AWS設定ファイル(~/.aws/config)
- ロールの引き受けの提供
- Boto2設定ファイル(/etc/boto.cfg and ~/.boto)
- IAMロールを構成されたAmazon EC2インスタンス上ではそのインスタンスメタデータサービス
本記事のサンプルコードでは認証情報を環境変数で設定します。
import os
os.environ["AWS_ACCESS_KEY_ID"] = "xxxx"
os.environ["AWS_SECRET_ACCESS_KEY"] = "xxxx"
os.environ["AWS_SESSION_TOKEN"] = "xxxx"
Boto3のインターフェイス
Boto3にはクライアントインターフェイスとリソースインターフェイスがあります(ドキュメント)。
- クライアントインターフェイス
- 低レベルのインターフェイス。サービスAPIに1対1で対応し、DynamoDB が提供するすべてのAPIを利用できる。一方で、多くの場合、より冗長で使い方が複雑。
- リソースインターフェイス
- 上位レベルのインターフェイス。サービスAPIと1対1で対応するわけではない。つまり、リソースインターフェイスで使用できないAPIもある。一方で、batch_writerなどのサービスへのアクセスが便利。
リソースインターフェイスの改修は今後凍結されるようです(参考)。
本記事では、クライアントインターフェイスを使用します。
import boto3
client = boto3.client('dynamodb', region_name='ap-northeast-1')
DynamoDBの各種操作
以下のサンプルコードは、こちらのドキュメントを参考にしています。
テーブルの作成
response = client.create_table(
TableName='People',
KeySchema=[
{
'AttributeName': 'PersonID',
'KeyType': 'HASH' # プライマリーキー
},
],
AttributeDefinitions=[
{
'AttributeName': 'PersonID',
'AttributeType': 'N' # 数値
},
],
ProvisionedThroughput={
"ReadCapacityUnits": 10, # 1秒間に最大10回の4KBまでのデータ読み取りをサポート
"WriteCapacityUnits": 10, # 1秒間に最大5回の1KBまでのデータ書き込みをサポート
},
)
項目の追加
response = client.put_item(
Item={
'PersonID': {
'N': '101',
},
'LastName': {
'S': 'Suzuki',
},
'FirstName': {
'S': 'Taro',
},
'Age': {
'N': '28',
},
'Phone': {
'S': '090-1234-5678',
},
'Address': {
'M': {
'Street': {'S': '1-2-3 Jingumae'},
'City': {'S': 'Shibuya-ku, Tokyo'},
'Zip Code': {'S': '150-0001'},
'Country': {'S': 'Japan'},
}
},
},
ReturnConsumedCapacity='TOTAL', # 消費された書き込み容量単位の総数を返す。
TableName='People',
)
複数の項目をまとめて追加する場合
response = client.batch_write_item(
RequestItems={
'People': [
{
'PutRequest': {
'Item': {
'PersonID': {
'N': '102',
},
'LastName': {
'S': 'Tanaka',
},
'FirstName': {
'S': 'Takuro',
},
'Phone': {
'S': '090-1111-1111',
},
},
},
},
{
'PutRequest': {
'Item': {
'PersonID': {
'N': '103',
},
'LastName': {
'S': 'Yamada',
},
'FirstName': {
'S': 'Jiro',
},
'Phone': {
'S': '090-2222-2222',
},
},
},
},
],
},
)
print(response)
項目の取得
1つの項目を追加する場合
response = client.get_item(
Key={
'PersonID': {
'N': '101',
},
},
TableName='People',
)
print(response)
Query
以下の例では、Peopleテーブルの項目を取得します。 このテーブルにはパーティション・キー(PersonID)がありますが、このクエリはパーティション・キーを指定します。 以下のクエリーは、”102″の人を返します。
response = client.query(
# KeyConditionExpressionで置換される値を定義
ExpressionAttributeValues={
':v1': {
'N': '102',
},
},
# PersonIDがExpressionAttributeValuesで定義したv1に等しい項目を取得
KeyConditionExpression='PersonID = :v1',
TableName='People',
)
print(response)
Scan
以下の例では、Peopleテーブル全体をスキャンし、その結果をPersonID “102”の人に絞り込んでいます。各項目について、LastNameとFirstNameだけが返されます。
response = client.scan(
ExpressionAttributeNames={
'#LN': 'LastName',
'#FN': 'FirstName',
},
ExpressionAttributeValues={
':p': {
'N': '102',
},
},
FilterExpression='PersonID = :p',
ProjectionExpression='#LN, #FN',
TableName='People',
)
print(response)
項目の削除
1つの項目を削除する場合
response = client.delete_item(
Key={
'PersonID': {
'N': '101',
},
},
TableName='People',
)
print(response)
複数の項目をまとめて削除する場合
response = client.batch_write_item(
RequestItems={
'People': [
{
'DeleteRequest': {
'Key': {
'PersonID': {
'N': '102',
},
},
},
},
{
'DeleteRequest': {
'Key': {
'PersonID': {
'N': '103',
},
},
},
},
],
},
)
print(response)
テーブルの削除
response = client.delete_table(
TableName='People'
)
コメント