我正在使用 DynamoDB,我需要更新多个记录上的特定属性。用伪语言编写我的要求,我想做一个更新,内容为“更新表persons设置relationshipStatus ='已婚'其中personKey IN(key1,key2,key3,...)”(假设personKey是KEY在我的 DynamoDB 表中)。
换句话说,我想用 IN 子句进行更新,或者我想可以将其称为批量更新。我发现 this 链接明确询问是否存在批量更新等操作,答案是不存在。然而,它没有提到 IN 子句。 文档显示条件表达式支持 IN 子句(一次可以提供 100 个值)。但是,我不确定这样的 IN 子句是否适合我的情况,因为我仍然需要提供强制 KEY 属性(它似乎需要一个值 - 我可能是错的)并且我担心它会做每次更新都会进行全表扫描。
所以我的问题是:如何同时实现多个 DynamoDB 记录的更新?目前看来我几乎必须为每个键一一调用更新语句,这感觉真的很错误......
正如您所指出的,DynamoDB 不支持批量更新操作。您需要查询并获取要更新的所有记录的键。然后循环遍历该列表,一次更新每一项。
我不知道自从给出答案后它是否已经改变,但现在有可能了
查看文档: 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% 确定) - 否则包装函数将非常简单组装
DynamoDb 并未设计为关系型数据库来支持本机事务。最好在设计架构时就避免出现多次更新的情况。或者,如果它对您的情况不实用,请记住您可以在重组设计时对其进行改进。
同时更新多个项目的唯一方法是使用 DynamoDB 提供的 TransactionWrite 操作。但它有一个限制(例如最多 25 个)。因此请记住这一点,您可能也应该在您的应用程序中进行一些限制。尽管成本非常高(因为实现涉及一些共识算法),但它仍然比简单的循环快得多。它为您提供了 ACID 属性,这可能是我们最需要的。想象一下使用循环的情况,如果其中一个更新失败,你如何处理失败?是否可以回滚所有更改而不引起某些竞争条件?更新是幂等的吗?这实际上取决于您应用原因的性质。小心点。
另一种选择是使用线程池来完成网络 I/O 作业,这肯定可以节省大量时间,但它也有同样的失败和回滚问题需要考虑。
我最近不得不这样做(更新数百个项目)并有一个 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