やりたいこと
既存のAWSのDynamoDBに存在するテーブル群を、そのまま複製したい
(TABLE_A
というテーブルがあるとき、TABLE_A_COPY
というテーブルを作りたい)
-
TABLE_A_COPY
は、TABLE_A
と同じテーブル定義であってほしい -
TABLE_A_COPY
には、TABLE_A
に登録されているアイテムがすべて登録されていてほしい - 上記を複数テーブルに対して行いたい
ちなみに、その理由は「テストで使いたいから」ですが、やってること自体はテストと関係ないので他の用途でも使えると思います。
大雑把な流れ
以下の処理を、複製したいテーブルの数だけ繰り返す
- 既存のテーブルのテーブル定義を取得して、ファイルに出力する
- 1 で作成したファイルを、
aws dynamodb create-table
で使用できる形に整形する (そのままだと、不要なデータがいっぱいあってエラーになるので) - 2 で整形したファイルを使って、新しいテーブルを作成する
- 既存のテーブルに登録されているアイテム情報を取得して、ファイルに出力する
- 4 で作成したファイルからアイテム情報を読み込み、新しいテーブルに登録する
使用するツール
- [AWS CLI] (https://aws.amazon.com/jp/cli/)
- [jq] (https://stedolan.github.io/jq/)
実際のスクリプト (データ作成先はローカル)
copy_table_for_test.sh
# !/bin/bash
# 元テーブルのテーブル定義から、create-table用のテーブル定義ファイルを作成する
get_table_data() {
# AWSから元テーブルのテーブル定義を取得してファイルに出力
aws dynamodb describe-table --table-name ${original_table_name} > ${original_table_file}
# AWSから出力したテーブル定義を、create-tableに使用できる形に成形してファイルに出力
cat ${original_table_file} |
jq '.Table' |
jq '.TableName = "'${new_table_name}'"' |
jq 'del(.TableStatus)' |
jq 'del(.CreationDateTime)' |
jq 'del(.ProvisionedThroughput.LastIncreaseDateTime)' |
jq 'del(.ProvisionedThroughput.NumberOfDecreasesToday)' |
jq 'del(.TableSizeBytes)' |
jq 'del(.ItemCount)' |
jq 'del(.TableArn)' |
jq 'del(.TableId)' |
jq 'del(.LatestStreamLabel)' |
jq 'del(.LatestStreamArn)' |
jq 'del(.GlobalSecondaryIndexes[]?.IndexStatus)' |
jq 'del(.GlobalSecondaryIndexes[]?.IndexSizeBytes)' |
jq 'del(.GlobalSecondaryIndexes[]?.ItemCount)' |
jq 'del(.GlobalSecondaryIndexes[]?.IndexArn)' |
jq 'del(.GlobalSecondaryIndexes[]?.ProvisionedThroughput.NumberOfDecreasesToday)' > ${new_table_file}
}
# 元テーブルのテーブル定義ファイルを元に、テスト用のテーブルを新規作成する
create_table() {
aws dynamodb create-table --cli-input-json file://${new_table_file} --endpoint-url http://localhost:8000
}
# 元テーブルに登録されているアイテム情報を、ファイルに出力する
get_items_data() {
aws dynamodb scan --table-name ${table_name} > ${original_items_file}
}
# 元テーブルのアイテム情報ファイルを元に、テスト用のテーブルにアイテムを登録する
put_items() {
# 登録対象のアイテム数
item_length=$(cat ${original_items_file} | jq ".Items | length")
# アイテム数 > 0 の場合のみ、テスト用テーブルにアイテムを登録する
# (アイテムが無いのに put-itemコマンド実行しようとするとエラーになるので)
if [ ${item_length} -gt 0 ]; then
for i in $( seq 0 $((${item_length} - 1)) ); do
item=$(cat ${original_items_file} | jq ".Items[${i}]")
aws dynamodb put-item --table-name ${new_table_name} --item "${item}" --endpoint-url http://localhost:8000
done
fi
}
# テスト用に複製するテーブル群のテーブル名を指定
target_tables=("TABLE_A" "TABLE_B" "TABLE_C")
for table_name in ${target_tables[@]}; do
# テーブル名
original_table_name=${table_name}
new_table_name=${original_table_name}_copy
# テーブル定義ファイル名
original_table_file=original_table_${original_table_name}.json
new_table_file=new_table_${new_table_name}.json
# アイテム情報ファイル名
original_items_file=original_items_${original_table_name}.json
get_table_data
create_table
get_items_data
put_items
done
注意点
- 手元のテーブル群に対してはこれで成功したけど、コピー元のテーブルの設定によっては
get_table_data()
内でやってるJSONファイル整形処理をもっと増やさないといけない可能性があります。 - 上記のスクリプトでは、新しいテーブルの作成先はローカルの DynamoDB にしています。
--endpoint-url http://localhost:8000
を削除すると、ローカルじゃなくてクラウド上にテーブル作成します。
参考
- [既存のDynamoDBテーブルからテーブル定義を作成する]
(https://www.hands-lab.com/tech/entry/188.html) - [既存のDynamoDBのテーブルをjsonフォーマットに変換するワンライナー] (https://qiita.com/uzresk/items/db4c7c7d6d783159c26c)