boto3を用いたDynamoDBの操作(2/3)

 
この記事は前回のboto3ライブラリを用いたDynamoDBの操作の続きです。

nissin-geppox.hatenablog.com





 

QueryとScan

 
ここでは、Batch writeを用いて複数の要素を一度に書き込みました。
 
また、書き込んだ要素をQueryやScanを用いて探索しました。

 
以降、実際のコードと出力を示します。

 
まず、必要なライブラリをインポートし、Batch writeでテーブルに要素を書き込みました。

入力

import json

with open("data.json", "r") as f:
    data = json.load(f)

with table.batch_writer() as batch:
    for d in data:
        batch.put_item(Item=d)

 
次に、用意したテーブルに対してpartition keyを用いてQueryを実行しました。

入力

from boto3.dynamodb.conditions import Key, Attr

resp = table.query(
    KeyConditionExpression=Key('username').eq('namihei_isono')
)
pprint(resp.get("Items"))

出力

[{'age': Decimal('54'),
  'date': '2021-07-25T10:00:00',
  'dose': Decimal('1'),
  'first_name': 'Namihei',
  'last_name': 'Isono',
  'prefecture': 'Chiba',
  'status': 'completed',
  'username': 'namihei_isono'},
 {'age': Decimal('54'),
  'date': '2021-08-20T10:00:00',
  'dose': Decimal('2'),
  'first_name': 'Namihei',
  'last_name': 'Isono',
  'prefecture': 'Chiba',
  'status': 'completed',
  'username': 'namihei_isono'}]

この出力結果より、partition keyであるusernameがnamihei_isonoという値を持つ要素を探し出すことができました。
 
次に、"一回目のワクチンのデータ"を指定してQueryを実行しました。

入力

resp = table.query(
    KeyConditionExpression=Key("username").eq("namihei_isono") & Key('dose').eq(1)
)
pprint(resp.get("Items"))

出力

[{'age': Decimal('54'),
  'date': '2021-07-25T10:00:00',
  'dose': Decimal('1'),
  'first_name': 'Namihei',
  'last_name': 'Isono',
  'prefecture': 'Chiba',
  'status': 'completed',
  'username': 'namihei_isono'}]

この出力結果より、正しい要素を探し出すことができました。
 
次に、ageの属性を用いてQueryを実行しました。

入力

resp = table.query(
    IndexName="ItemsByAge",
    KeyConditionExpression=Key('age').eq(11),
)
pprint(resp.get("Items"))

出力

[{'age': Decimal('11'),
  'date': '2021-07-20T10:00:00',
  'dose': Decimal('1'),
  'first_name': 'Katsuo',
  'last_name': 'Isono',
  'prefecture': 'Gunma',
  'status': 'reserved',
  'username': 'katsuo_isono'}]

この出力結果より、11歳のage属性をもつ要素を探し出すことができました。
 
また、prefectureの属性を用いてQueryを実行しました。

入力

resp = table.query(
    IndexName="ItemsByPrefecture",
    KeyConditionExpression=Key('prefecture').eq("Tokyo"),
)
pprint(resp.get("Items"))

出力

[{'age': Decimal('3'),
  'date': '2021-07-20T10:00:00',
  'dose': Decimal('1'),
  'first_name': 'Tarao',
  'last_name': 'Huguta',
  'prefecture': 'Tokyo',
  'status': 'reserved',
  'username': 'tarao_huguta'},
 {'age': Decimal('28'),
  'date': '2021-07-20T10:00:00',
  'dose': Decimal('1'),
  'first_name': 'Huguta',
  'last_name': 'Masuo',
  'prefecture': 'Tokyo',
  'status': 'reserved',
  'username': 'masuo_huguta'}]

この出力結果より、住所が東京にある要素を2つ探し出すことができました。
 
次に、検索条件を指定せずにScanを実行した。

入力

resp = table.scan()
items = resp.get("Items")
print("Number of items:", len(items))

出力

Number of items: 8

この出力結果より、要素が8個あることが確認できました。
 
また、Scanは一度に1MBのデータを探索し、上限に達した時点のデータをユーザーに戻します。よって、1MBを超えるデータを探索するには以下の入力のようにLastEvakuatedKeyのような変数を設け、再帰的に探索を実行する必要があります。

入力

resp = table.scan()
items = resp.get("Items")
while resp.get("LastEvaluatedKey"):
    resp = table.scan(ExclusiveStartKey=r["LastEvaluatedKey"])
    items.extend(resp["Items"])
print("Number of items", len(items))

出力

Number of items 8

出力結果は、先ほどの探索結果と同じになります。
 
次に、Scanを用いて条件を満たす要素の探索を行った。

入力

resp = table.scan(
    FilterExpression=Attr('age').lt(27)
)
pprint(resp.get("Items"))

出力

[{'age': Decimal('9'),
  'date': '2021-07-20T10:00:00',
  'dose': Decimal('1'),
  'first_name': 'Wakame',
  'last_name': 'Isono',
  'prefecture': 'Saitama',
  'status': 'reserved',
  'username': 'wakame_isono'},
 {'age': Decimal('3'),
  'date': '2021-07-20T10:00:00',
  'dose': Decimal('1'),
  'first_name': 'Tarao',
  'last_name': 'Huguta',
  'prefecture': 'Tokyo',
  'status': 'reserved',
  'username': 'tarao_huguta'},
 {'age': Decimal('11'),
  'date': '2021-07-20T10:00:00',
  'dose': Decimal('1'),
  'first_name': 'Katsuo',
  'last_name': 'Isono',
  'prefecture': 'Gunma',
  'status': 'reserved',
  'username': 'katsuo_isono'}]

この出力結果より、27歳以下の要素を探し出すことができました。
 
次に、dateの属性を用いて特定の日時の一覧を取得しました。

入力

resp = table.scan(
    FilterExpression=Attr('date').begins_with("2021-07-25"),
)
pprint(resp.get("Items"))

出力

[{'age': Decimal('54'),
  'date': '2021-07-25T10:00:00',
  'dose': Decimal('1'),
  'first_name': 'Namihei',
  'last_name': 'Isono',
  'prefecture': 'Chiba',
  'status': 'completed',
  'username': 'namihei_isono'}]

この出力結果より、日時が2021-07-25である要素を探し出すことができました。
 
最後に、要素の一部の属性を取り出しました。
 
今回はprefecture属性のみを返すようにしました。

入力

resp = table.scan(
    ProjectionExpression="first_name, prefecture"
)
pprint(resp.get("Items"))

出力

[{'first_name': 'Wakame', 'prefecture': 'Saitama'},
 {'first_name': 'Namihei', 'prefecture': 'Chiba'},
 {'first_name': 'Namihei', 'prefecture': 'Chiba'},
 {'first_name': 'Huguta', 'prefecture': 'Tokyo'},
 {'first_name': 'Hune', 'prefecture': 'Chiba'},
 {'first_name': 'Hune', 'prefecture': 'Chiba'},
 {'first_name': 'Tarao', 'prefecture': 'Tokyo'},
 {'first_name': 'Katsuo', 'prefecture': 'Gunma'}]

この出力結果より、要素のfast_nameとprefectureのみを取り出すことができました。