(我不担心原子性)。
创建一个备份(备份选项),并使用新表名还原表。这将使所有数据进入新表。 注意:根据表的大小需要相当长的时间。
我刚刚使用了 Python 脚本 dynamodb-copy-table,确保我的凭据保存在环境变量中(AWS_ACCESS_KEY_ID
和 AWS_SECRET_ACCESS_KEY
),然后它就完美地运行了。它甚至为我创建了目标表。
python dynamodb-copy-table.py src_table dst_table
默认区域是 us-west-2
,使用 AWS_DEFAULT_REGION
环境变量更改它。
我喜欢使用简单的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 table_v1 table_v2
这里有一个解决方案,可以使用 Shell 脚本、AWS CLI 和 jq工具将一个表中的所有项复制到另一个表中。适用于较小的表格。
# 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 中的所有项目。
使用“导出到S3”功能将整个表格转储到S3。由于这使用备份生成转储,因此不会影响表格的吞吐量,并且速度非常快。您需要启用备份(PITR)。请参见https://aws.amazon.com/blogs/aws/new-export-amazon-dynamodb-table-data-to-data-lake-amazon-s3/。
使用“从S3导入”来导入步骤1中创建的转储。这会自动要求您创建一个新表格。
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')
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>