如何一次更新 DynamoDB 表中的多个项目

问题描述 投票:0回答:5

我正在使用 DynamoDB,我需要更新多个记录上的特定属性。用伪语言编写我的要求,我想做一个更新,内容为“更新表persons设置relationshipStatus ='已婚'其中personKey IN(key1,key2,key3,...)”(假设personKey是KEY在我的 DynamoDB 表中)。

换句话说,我想用 IN 子句进行更新,或者我想可以将其称为批量更新。我发现 this 链接明确询问是否存在批量更新等操作,答案是不存在。然而,它没有提到 IN 子句。 文档显示条件表达式支持 IN 子句(一次可以提供 100 个值)。但是,我不确定这样的 IN 子句是否适合我的情况,因为我仍然需要提供强制 KEY 属性(它似乎需要一个值 - 我可能是错的)并且我担心它会做每次更新都会进行全表扫描。

所以我的问题是:如何同时实现多个 DynamoDB 记录的更新?目前看来我几乎必须为每个键一一调用更新语句,这感觉真的很错误......

amazon-web-services amazon-dynamodb nosql
5个回答
66
投票

正如您所指出的,DynamoDB 不支持批量更新操作。您需要查询并获取要更新的所有记录的键。然后循环遍历该列表,一次更新每一项。


19
投票

您可以使用 TransactWriteItems 操作更新 DynamoDB 表中的多条记录。

可以在这里找到官方文档,也可以在这里查看 TransactWriteItems javascript/nodejs 示例。


15
投票

我不知道自从给出答案后它是否已经改变,但现在有可能了

查看文档: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html

我在 JavaScript 中像这样使用它(将新块映射到具有所需结构的对象数组:

let params = {}
let tableName = 'Blocks';

params.RequestItems[tableName] = _.map(newBlocks, block => {
    return {
        PutRequest: {
            Item: {
                'org_id': orgId,
                'block_id': block.block_id,
                'block_text': block.block_text
            },
            ConditionExpression: 'org_id <> :orgId AND block_id <> :block_id',
            ExpressionAttributeValues: {
                ':orgId': orgId,
                ':block_id': block.block_id
            }
        }
    }
})

docClient.batchWrite(params, function(err, data) {
   .... and do stuff with the result

您甚至可以混合

puts
deletes

如果您使用dynogels(由于dynogels支持,您不能混合它们,但您可以做的是更新(使用create,因为在幕后它会像put一样转换为batchWrite函数)

var item1 = {email: '[email protected]', name: 'Foo 1', age: 10};
var item2 = {email: '[email protected]', name: 'Foo 2', age: 20};
var item3 = {email: '[email protected]', name: 'Foo 3', age: 30};

Account.create([item1, item2, item3], function (err, acccounts) {
  console.log('created 3 accounts in DynamoDB', accounts);
});

请注意 DynamoDB 限制(来自文档):

BatchWriteItem 操作可在一个或多个表中放置或删除多个项目。对 BatchWriteItem 的单次调用最多可写入 16 MB 的数据,其中可包含多达 25 个放置或删除请求。要写入的单个项目最大可达 400 KB。

如果我没记错的话,我认为 dynogels 会将请求分成 25 个块,然后发送出去,然后将它们收集在一个承诺中并返回(尽管我对此不是 100% 确定) - 否则包装函数将非常简单组装


9
投票

DynamoDb 并未设计为关系型数据库来支持本机事务。最好在设计架构时就避免出现多次更新的情况。或者,如果它对您的情况不实用,请记住您可以在重组设计时对其进行改进。

同时更新多个项目的唯一方法是使用 DynamoDB 提供的 TransactionWrite 操作。但它有一个限制(例如最多 25 个)。因此请记住这一点,您可能也应该在您的应用程序中进行一些限制。尽管成本非常高(因为实现涉及一些共识算法),但它仍然比简单的循环快得多。它为您提供了 ACID 属性,这可能是我们最需要的。想象一下使用循环的情况,如果其中一个更新失败,你如何处理失败?是否可以回滚所有更改而不引起某些竞争条件?更新是幂等的吗?这实际上取决于您应用原因的性质。小心点。

另一种选择是使用线程池来完成网络 I/O 作业,这肯定可以节省大量时间,但它也有同样的失败和回滚问题需要考虑。


0
投票

我最近不得不这样做(更新数百个项目)并有一个 bash 脚本来帮助完成该过程。

假设您有一个名为“big.json”的文件,其中包含您想要执行的所有语句。它看起来像这样:

[
    {
        "Statement":"UPDATE some_table SET some_column = 123 WHERE key_column = 000"
    },
    {
        "Statement":"UPDATE some_table SET some_column = 456 WHERE key_column = 999"
    },
    ...etc
]

然后您可以执行以下操作,将该文件拆分为 25 个或更少的较小批次,并运行所有这些较小批次。

#make temp directory
temp_dir=$(mktemp -d)
cd $temp_dir
#split into batches of 25
jq -cM --argjson sublen '25' 'range(0; length; $sublen) as $i | .[$i:$i+$sublen]' big.json | split -l 1 -da 3 - batch_
#run the aws batch command for all (put output into text file)
ls -1a batch_* | sed -E "s/(.*)/file:\/\/\1/g" | xargs -I XXXfileXXX aws dynamodb batch-execute-statement --no-cli-pager --statements XXXfileXXX > output.txt
© www.soinside.com 2019 - 2024. All rights reserved.