在DynamoDB中将一个表复制到另一个表

66
什么是在DynamoDB中将一张表完全复制到另一张表的最佳方法?
(我不担心原子性)。

请使用 https://www.npmjs.com/package/dynamo-copy。 - Dipankar Naskar
15个回答

54

创建一个备份(备份选项),并使用新表名还原表。这将使所有数据进入新表。 注意:根据表的大小需要相当长的时间。


3
如果您的使用情况与我的类似,只需要为测试创建一个副本表,不关心原子性或者两个表格中的更新情况,那么这非常有用。 - CustardBun

50

我刚刚使用了 Python 脚本 dynamodb-copy-table,确保我的凭据保存在环境变量中(AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY),然后它就完美地运行了。它甚至为我创建了目标表。

python dynamodb-copy-table.py src_table dst_table

默认区域是 us-west-2,使用 AWS_DEFAULT_REGION 环境变量更改它。


4
太棒了,使用起来非常顺畅而且非常简单!可惜这个答案只有0票,所以我差点错过它。+1 - Till Kuhn
1
如果您不在us-west-2,则还需要设置AWS_DEFAULT_REGION。 - Tony BenBrahim
2
如果目标表已存在,设置DISABLE_CREATION=true。 - Francisco Cardoso
似乎不支持AWS配置文件,遗憾。 - killthrush

19

16
很遗憾,这个模板似乎已经从数据管道控制台消失了。 - joelittlejohn

9

我喜欢使用简单的bash脚本来完成这个想法,所以我决定采用@bogdan-kiselitsa的优秀答案,并将其扩展到超过25个项目的表格。

# exit on error
set -eo pipefail

# tables
TABLE_FROM=$1
TABLE_TO=$2

# read
aws dynamodb scan \
  --table-name "$TABLE_FROM" \
  --output json \
 | jq "[ .Items[] | { PutRequest: { Item: . } } ]" \
 > "$TABLE_FROM-dump.json"

table_size="$(cat "${TABLE_FROM}-dump.json" | jq '. | length')"
echo "table size: ${table_size}"

# write in batches of 25
for i in $(seq 0 25 $table_size); do
  j=$(( i + 25 ))
  cat "${TABLE_FROM}-dump.json" | jq -c '{ "'$TABLE_TO'": .['$i':'$j'] }' > "${TABLE_TO}-batch-payload.json"
  echo "Loading records $i through $j (up to $table_size) into ${TABLE_TO}"
  aws dynamodb batch-write-item --request-items file://"${TABLE_TO}-batch-payload.json"
  rm "${TABLE_TO}-batch-payload.json"
done


# clean up
rm "${TABLE_FROM}-dump.json"

如果您将此保存为migrate.sh,则可以运行以下命令:
$ ./migrate.sh table_v1 table_v2

1
非常完美。感谢您的帮助。 - undefined

7

这里有一个解决方案,可以使用 Shell 脚本、AWS CLIjq工具将一个表中的所有项复制到另一个表中。适用于较小的表格。

# exit on error
set -eo pipefail

# tables
TABLE_FROM=<table>
TABLE_TO=<table>

# read
aws dynamodb scan \
  --table-name "$TABLE_FROM" \
  --output json \
 | jq "{ \"$TABLE_TO\": [ .Items[] | { PutRequest: { Item: . } } ] }" \
 > "$TABLE_TO-payload.json"

# write
aws dynamodb batch-write-item --request-items file://"$TABLE_TO-payload.json"

# clean up
rm "$TABLE_TO-payload.json"

如果你想让两个表完全相同,你需要先删除 TABLE_TO 中的所有项目。


5
由于批量写入项目不允许导入超过25个项目,因此此处限制为25个项目。 - jamiegs
对于小型操作非常有帮助。 - flymg

7
你可以使用扫描来读取数据并将其保存到新表中。
在AWS论坛上,AWS团队的一位成员发布了另一种使用EMR的方法:如何复制表?

2
链接不再可用。 - Eagl3

5
DynamoDB现在支持从S3导入。

https://aws.amazon.com/blogs/database/amazon-dynamodb-can-now-import-amazon-s3-data-into-a-new-table/

因此,在几乎所有的用例中,复制表格最简单、最便宜的方法可能是:
  1. 使用“导出到S3”功能将整个表格转储到S3。由于这使用备份生成转储,因此不会影响表格的吞吐量,并且速度非常快。您需要启用备份(PITR)。请参见https://aws.amazon.com/blogs/aws/new-export-amazon-dynamodb-table-data-to-data-lake-amazon-s3/

  2. 使用“从S3导入”来导入步骤1中创建的转储。这会自动要求您创建一个新表格。


3

Python + boto3

只要您保持相同的键,该脚本就是幂等的。

import boto3


def migrate(source, target):
    dynamo_client = boto3.client('dynamodb', region_name='us-east-1')
    dynamo_target_client = boto3.client('dynamodb', region_name='us-west-2')

    dynamo_paginator = dynamo_client.get_paginator('scan')
    dynamo_response = dynamo_paginator.paginate(
        TableName=source,
        Select='ALL_ATTRIBUTES',
        ReturnConsumedCapacity='NONE',
        ConsistentRead=True
    )
    for page in dynamo_response:
        for item in page['Items']:
            dynamo_target_client.put_item(
                TableName=target,
                Item=item
            )


if __name__ == '__main__':
    migrate('awesome-v1', 'awesome-v2')


2

实际上,我在 RunKit 上使用了这个包,在一个小表格上它运行良好,是的,我是个懒惰的土豆。 - mcanvar

2
这是我写的一个小脚本,用于将一个表格的内容复制到另一个表格中。它基于AWS-SDK v3开发,但不确定它在处理大型表格时的可扩展性如何,但作为一个快速而简单的解决方案,它能够胜任。
它会从~/.aws/credentials文件中获取你的AWS凭证,将"default"改为你想要使用的配置文件的名称。
除此之外,它需要两个参数,一个用于源表格,一个用于目标表格。
const { fromIni } = require("@aws-sdk/credential-providers");
const { DynamoDBClient, ScanCommand, PutItemCommand } = require("@aws-sdk/client-dynamodb");

const ddbClient = new DynamoDBClient({
  credentials: fromIni({profile: "default"}),
  region: "eu-west-1",
});

const args = process.argv.slice(2);
console.log(args)

async function main() {

  const { Items } = await ddbClient.send(
    new ScanCommand({
      TableName: args[0],
    })
  );
  console.log("Successfully scanned table")
  console.log("Copying", Items.length, "Items")

  const putPromises = [];

  Items.forEach((item) => {
    putPromises.push(
      ddbClient.send(
        new PutItemCommand({
          TableName: args[1],
          Item: item,
        })
      )
    );
  });

  await Promise.all(putPromises);
  console.log("Successfully copied table")
}

main();

使用方法

node copy-table.js <source_table_name> <destination_table_name>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接