はじめに
本記事ではDynamoDBのGSI(Global Secondary Index)を作成し、Lambdaからクエリを実行する処理を実装していきます。
ゴール
DynamoDBのGSIに対してLambdaからクエリを実行し、パーティションキーとソートキーの条件に一致する項目から、特定の属性値のみを取得します。
下記のようなGSIを作成し、user1
の user_status:active
を取得する処理を実装します。
▼GSI例
userId(パーティションキー) | timestamp(ソートキー) | user_status |
---|---|---|
user1 | 2024-11-07 | active |
user2 | 2024-11-08 | active |
作るもの
- DynamoDBのテーブル:1つ
- GSI:1つ
- Lambda:1つ
書かない事
IAMの権限については本記事では記載しておりません。
1. DynamoDBのテーブルを作成
次の5つの属性を持つテーブルを作成します。
- id (パーティションキー)
- userId
- timestamp
- user_status
- category
2. GSIを作成
次の3つの属性を持つインデックスを作成します。
- userId (GSIのパーティションキー)
- timestamp (GSIのソートキー)
- user_status (取得したい属性、Include > 属性名で選択)
次の図のようにインデックスタブから想定通りGSIを作成できている事を確認できました。
3. Lambdaを作成
import json
import boto3
from boto3.dynamodb.conditions import Key
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('test-1107-db')
def lambda_handler(event, context):
body = json.loads(event['body'])
user_id = body['userId']
specific_date = body['timestamp']
# GSIを使用したクエリ
response = table.query(
# インデックス名
IndexName='userId-timestamp-index',
# クエリ条件:userIdとtimestampが一致する項目を検索
KeyConditionExpression=Key('userId').eq(user_id) & Key('timestamp').eq(specific_date),
# user_statusのみを取得
ProjectionExpression='user_status'
)
return {
'statusCode': 200,
'body': json.dumps(response['Items'])
}
クエリ部分についてはAmazon DynamoDB > デベロッパーガイド記載の下記の部分を参考にしています。
リソースインターフェイスを使った同じクエリ操作を短くして簡略化できます。
import boto3
from boto3.dynamodb.conditions import Key, Attr
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('YourTableName')
response = table.query(
KeyConditionExpression=Key('pk').eq('id#1') & Key('sk').begins_with('cart#'),
FilterExpression=Attr('name').eq('SomeName')
)
引用:デベロッパーガイド
属性が値と等しいことを確認するために boto3.dynamodb.conditions.Key
を使用しています。今回使用したのは等価比較を行うための eq
です。
4. LambdaからGSIへのクエリを実行
test eventを作成してLabmdaを実行してみます。実行するイベントの内容は次の通りです。
{
"body": "{\"userId\": \"user1\", \"timestamp\": \"2024-11-07\"}"
}
GSIに保存している次の項目の user_status
を取得する想定です。
id (文字列):1
timestamp:2024-11-07
user_status:active
userId:user1
Lambdaを実行すると200で正常に下記のレスポンスを取得できました。
想定通り userId:user1
の user_status:active
のデータを取得できていることが確認できます。
{
"statusCode": 200,
"body": "[{\"user_status\": \"active\"}]"
}
参考