こんにちは太郎です。
最近、DynamoDBを触る機会があり1:nのデータ構造を表現しようとしました。
しかし、DynamoDB特有の設計方法に戸惑ったのでメモを残します。
前提条件
この先は例を挙げながら進めます。
ひとつのチームに複数の選手が所属しているという想定です。
チームの一覧を表示する画面と属する選手の一覧を表示する画面があります。
DynamoDBではRDBとは違い、どのようにデータにアクセスするのか次第で構造がかなり変わるため、最初にユースケースをリストアップすることが重要になってきます。
テーブル設計
RDBで設計するなら2つテーブルを作って、一方が片方を参照しているという設計が一般的かと思います。
しかし、DynamoDBではテーブルの数は極力減らすという方針があります。
それぞれの一覧が取得できるように以下のような設計にしました。
ID(PK) | dataType(GSI) | teamName | memberName | teamID |
---|---|---|---|---|
1 | team | teamA | ||
2 | team | teamB | ||
3 | member | memberA | 1 | |
4 | member | memberB | 1 | |
5 | member | memberC | 2 |
チーム一覧を取得する
上で設計したテーブルからチームの一覧を取得しようと思います。
グローバルセカンダリインデックス(GSI)にdataTypeを登録しています。
このGSIを使ってチームの一覧を取得しようと思います。
AWSのコンソールを使うと画像のようになるのですが、GoのSDKを使うと下のようになります。
params := &dynamodb.QueryInput{
TableName: aws.String("sample"),
ExpressionAttributeNames: map[string]*string{
"#dataType": aws.String("dataType"),
},
ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
":dataType": {
S: aws.String("team"),
},
},
KeyConditionExpression: aws.String("#dataType = :dataType"),
IndexName: aws.String("dataType-index"),
}
teamAに所属する選手の一覧を取得する
dataTypeがmemberかつ、teamIDが1の選手を取得します。
コンソールで操作すると画像のような感じです。
Goのコードも載せます。
params := &dynamodb.QueryInput{
TableName: aws.String("sample"),
ExpressionAttributeNames: map[string]*string{
"#dataType": aws.String("dataType"),
"#teamID": aws.String("teamID"),
},
ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
":dataType": {
S: aws.String("member"),
},
":teamID": {
S: aws.String("1"),
},
},
KeyConditionExpression: aws.String("#dataType = :dataType"),
FilterExpression: aws.String("#teamID = :teamID"),
IndexName: aws.String("dataType-index"),
}
まとめ
DynamoDBの操作は独特でSDKの扱いにも手こずりました。
下にGolangの全ソースコードを載せます。
参考
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/best-practices.html
https://qiita.com/_kensh/items/2351096e6c3bf431ff6f