DynamoDBでSQLのIN句のように複数条件を指定する

2023.10.17

はじめに

私が担当しているプロジェクトではDynamoDBを使っています。複数のパーティションキーを指定してデータを取得したいのですが、何度もGetItemすると時間がかかるのでSQLのIN句のように一括で取得する方法がないか調べました。

テーブル

サンプルとして以下のようなemployeeテーブルを作成しました。 id がパーティションキーでname, department_idを属性として持っています。

パーティションキーを複数指定して一括で取得する

上記のテーブルからデータを取得するLambdaファンクションをPythonで実装してみました。キーを複数指定して一括して取得する場合はbatch_get_itemを使っています。パーティションキーのidを複数指定できます。

import boto3
from boto3.dynamodb.conditions import Attr
dynamodb = boto3.resource('dynamodb')

def lambda_handler(event, context):
    requestItems = {'employee': {'Keys': [{'id': '00001'}, {'id': '00002'}]}}
    response = dynamodb.batch_get_item(RequestItems=requestItems)
    if "Responses" in response:
        items = response["Responses"].get('employee', [])
        for item in items:
            print(item)
    return


実行すると以下のような結果が出力されました。

{'id': '00001', 'department_id': '001', 'name': '名前1'}
{'department_id': '001', 'id': '00002', 'name': '名前2'}

batch_get_item は便利ですが注意点があります。それは一度に取得できる件数、データ量に制限があることです。制限を超える場合は何回かに分ければ取得できます。詳しくは以下の公式のページをご覧ください。また、batch_get_item はテーブルに対してのみ実行でき、インデックスに対しては実行できません。

AWS SDK を使用して DynamoDB 項目のバッチを取得する - Amazon DynamoDB

パーティションキー以外の属性を複数指定して一括で取得する

次にパーティションキーではないdepartment_id属性を条件にして一括取得しました。scanで全件取得した後にFilterExpressionで絞りこんでいます。

import boto3
from boto3.dynamodb.conditions import Attr
dynamodb = boto3.resource('dynamodb')

def lambda_handler(event, context):      
    table= dynamodb.Table('employee')
    response = table.scan(FilterExpression=Attr("department_id").is_in(['001', '003']))
    if "Items" in response:
        for item in response["Items"]:
            print(item)
    return


実行すると以下のような結果が出力されます。department_idが001と003のデータのみ取得できています。

{'department_id': '001', 'id': '00003', 'name': '名前3'}
{'department_id': '001', 'id': '00002', 'name': '名前2'}
{'id': '00001', 'department_id': '001', 'name': '名前1'}
{'department_id': '003', 'id': '00006', 'name': '名前6'}

この方法の注意点はscanはテーブルの全データを取得するため、データ量が多いほどキャパシティを多く消費することです。許容できない場合はグローバルセカンダリインデックスを作成して1件づつqueryで取得したほうがよさそうです。

PartiQL

DynamoDBにはPartiQLというSQL互換の言語を使うことができます。PartiQLにはIN句も使えますがパーティションキー以外は上記の様にscanしていると思われます。詳しくは以下のドキュメントをご覧ください。

DynamoDB 用の PartiQL select ステートメント

最後に

今回調べたことは以上になります。パーティションキー以外での一括取得は中々難しそうだと感じました。何度もDynamoDBにリクエストしなくてもいいように設計時点で気を付けたいですね。