LoginSignup
2
0

More than 1 year has passed since last update.

【DynamoDB】CLIで気軽にエクスポート、インポートを行う

Posted at

はじめに

DynamoDBから特定のデータをエクスポートし、値を一部変更した上で再度インポートするという要件があったので、これを AWS CLI で行ってみました。

DynamoDB のエクスポート/インポートは、AWS Data PipelineLambda と S3を使用することで可能になります。
しかし、どちらもちょっと手間がかかります。
そこで、手軽にできる AWS CLI を使用して検証してみました。

結論

データエクスポートにquery or scan
データ整形に jq
データインポートに batch-write-itemを使用しました。

スクリプトは以下の通りです。

# 初期化
next_token=

function scan() {
  # わかりやすいように scan API を関数に格納。インラインでもOK
  # batch-write-itemが一度に書き込めるのが25件なので、`--max-items 25` を使用
  # 前回のデータを取得時に、next_tokenが存在した場合はそれを指定。存在しない場合は空欄
  aws dynamodb scan \
    --table-name $your_table_name \
    --max-items 25 \
    $([ -z $next_token ] && echo "" || echo "--starting-token $next_token")
}

while [ "$next_token" != "null" ]; do
  # scan結果を、batch-write-itemで読める形に整形
  request_items=$(
    echo $cli_output \
      | jq '.Items[] | {PutRequest: {Item:.}}' \
      | jq -n "{\"$your_table_name\": [inputs]}"
  )
  aws dynamodb batch-write-item --request-items "$request_items"

  # next_token を格納 (無い場合はnullが入る)
  next_token=$(echo $cli_output | jq -r ".NextToken")
done

詳細

scanコマンドを使用した場合、以下のような形式のデータが出力されます。

{
    "Items": [
        { /** ここにデータ*/ },
        { ... },
        ...,
    ],
    "Count": 0,
    "ScannedCount": 0,
    "ConsumedCapacity": null,
    "NextToken": "aaaaaaaa" // or "null"
}

一方、batch-write-itemでインポートする際の形式は、以下の通りとなります。
そのため、jqコマンドを使用して上の形式を下の形式に変更しています。

{
  "your_table_name": [
    {
      "PutRequest": {
        "Item": { /** ここにデータ*/ },
      }
    },
    {
      "PutRequest": {
        "Item": { /** ここに2件目のデータ*/ },
      }
    },
    ...,
  ]
}

また、scan した件数より出力した件数が少ない場合、nextTokenが返されるので、2 回目以降はそのnextToken--starting-tokenパラメータに指定します。
参考: AWS CLI ページ分割オプションの使用 - AWS コマンドラインインターフェイス

デモ

実際にテーブルを用意し、データのエクスポートとインポートを行います。
要件は、yaerが2013年のデータをエクスポートし、2021年に書き換えた上で、同じテーブルに違うデータとしてインポートするとします。

1. 準備

こちらのページを参考にテーブルの作成とデータの追加を行います。

# テーブル作成
$ aws dynamodb create-table \
  --attribute-definitions '
      [
        { "AttributeName": "year", "AttributeType": "N" },
        { "AttributeName": "title", "AttributeType": "S" }
      ]' \
  --table-name Movies \
  --key-schema '
      [
        { "AttributeName": "year", "KeyType": "HASH" },
        { "AttributeName": "title", "KeyType": "RANGE" }
      ]' \
  --provisioned-throughput '
      {
          "ReadCapacityUnits": 10,
          "WriteCapacityUnits": 10
      }'

サンプルデータは、こちらのmoviedata.zipを使います。

# データの登録
# 1 行ずつ処理するために、json オブジェクトを 1 行で表示する `-c`オプションを使用
$ IFS=$'\n'; for item in $(cat moviedata.json| jq -c '.[:20] | .[]'); do
  aws dynamodb put-item \
  --table-name Movies \
  --item  "{
    \"year\": {\"N\": \"$(echo $item | jq .year)\"},
    \"title\": {\"S\": $(echo $item | jq .title)}
  }"
done

2. データのエクスポート/インポート

# データ確認用
OUTPUT_FILE="output.json"
# 初期化
next_token=

function scan() {
  # わかりやすいように scan API を関数に格納。インラインでもOK
  # yearが2013年のデータを抽出
  # year は予約後なので、 `--expression-attribute-names` を用いて `#year`というプレースホルダーを用意する
  # 前回のデータを取得時に、next_tokenが存在した場合はそれを指定。存在しない場合は空欄
  aws dynamodb scan \
    --table-name Movies \
    --filter-expression '#year = :year' \
    --expression-attribute-values '{":year":{"N":"2013"}}' \
    --expression-attribute-names '{"#year": "year"}' \
    --max-items 25 \
    $([ -z $next_token ] && echo "" || echo "--starting-token $next_token")
}

while [ "$next_token" != "null" ]; do
  # scan結果を、year書き換え後にbatch-write-itemで読める形に整形
  request_items=$(
    echo $cli_output \
      | jq '.Items[].year.N="2021"' \
      | jq '.Items[] | {PutRequest: {Item:.}}' \
      | jq -n '{"Movies": [inputs]}'
  )
  echo $request_items >> $OUTPUT_FILE
  aws dynamodb batch-write-item --request-items "$request_items"

  # next_token を格納 (無い場合はnullが入る)
  next_token=$(echo $cli_output | jq -r ".NextToken")
done

実際に DB を確認すると、データが増えているのが確認できるかと思います。

参考

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0