DynamoDB - 如果散列(或散列和范围组合)不存在,则放置项目

mro*_*rog 27 amazon-dynamodb

以下是我的用例:我有一个带有散列+范围键的Dynamo表.当我在表中放入新项目时,我想进行唯一性检查.有时我想保证散列是唯一的(忽略范围).其他时候我想允许重复哈希,但保证哈希和范围组合是唯一的.我怎么能做到这一点?

我尝试了attribute_not_exists.它似乎处理第二种情况,它检查哈希+键组合.这是一个PHP示例:

$client->putItem(array(
    'TableName' => 'test',
    'Item' => array(
        'hash' => array('S' => 'abcdefg'),
        'range' => array('S' => 'some other value'),
        'whatever' => array('N' => 233)
    ),
    'ConditionExpression' => 'attribute_not_exists(hash)'
));
Run Code Online (Sandbox Code Playgroud)

奇怪的是,如果我使用attribute_not_exists(hash)或者似乎并不重要attribute_not_exists(range).他们似乎都做了完全相同的事情.这是它应该如何工作?

知道如何处理我只想检查hash唯一性的情况吗?

mko*_*bit 43

你不能.DynamoDB中的所有项目都由其hashhash+ range(取决于您的表)索引.

到目前为止发生了什么的总结:

  • 单个散列键可以具有多个范围键.
  • 每个项目都有一个hash和一个range
  • 您正在提出PutItem请求,并且必须提供hashrange
  • 您在或属性名称上提供了ConditionExpressionwithattribute_not_existshashrange
  • attribute_not_exists条件只是检查是否具有该名称的属性存在,它并不关心价值

让我们来看一个例子.让我们从带有这些数据的hash+ rangekey表开始:

  1. hash=A,range=1
  2. hash=A,range=2

有四种可能的情况:

  1. 如果你试图用hash=A,range=3和放置一个项目attribute_not_exists(hash),那么PutItem将成功,因为attribute_not_exists(hash)评估为true.没有项目存在hash=A,range=3满足条件的键attribute_not_exists(hash).

  2. 如果你试图用hash=A,range=3和放置一个项目attribute_not_exists(range),那么PutItem将成功,因为attribute_not_exists(range)评估为true.没有项目存在hash=A,range=3满足条件的键attribute_not_exists(range).

  3. 如果您尝试使用hash=A,range=1和放置项目attribute_not_exists(hash),PutItem则会因为attribute_not_exists(hash)求值而失败false.存在具有hash=A,range=1不满足条件的键的项attribute_not_exists(hash).

  4. 如果您尝试使用hash=A,range=1和放置项目attribute_not_exists(range),PutItem则会因为attribute_not_exists(range)求值而失败false.存在具有hash=A,range=1不满足条件的键的项attribute_not_exists(range).

这意味着将发生以下两件事之一:

  1. hash+ range对存在于数据库中.
    • attribute_not_exists(hash) 一定是 true
    • attribute_not_exists(range) 一定是 true
  2. hash+ range对不存在于数据库中.
    • attribute_not_exists(hash) 一定是 false
    • attribute_not_exists(range) 一定是 false

在这两种情况下,无论是将其放在哈希值还是范围键上,都会得到相同的结果.该hash+ range键标识在整个表中的单个项目,你的病情正在对项目进行评估.

如果具有此hash+ range键的项目尚不存在,您实际上正在执行"放置此项目".

  • 好的,现在才有意义.我认为attribute_not_exists正在寻找一个与插入记录中的属性值相同的属性.实际上,价值无关紧要.它实际上是在寻找具有相同主键和具有提供名称的属性(任何值)的现有项目.谢谢! (12认同)
  • 我仍然不清楚为什么会这样。如果我插入一个哈希值为“ 123”且范围为“ abc”的项目,则“ attribute_not_exists(hash)”将阻止我插入另一个具有相同哈希值和范围的项目。但是,即使它具有与第一个项目相同的哈希值,也不会阻止我插入具有“ 123”和范围“ xyz”的项目。即使范围值不同,我该如何避免重复的哈希值呢? (2认同)
  • @mrog 那是因为 `hash`+`range` 表的设计方式。一个散列键可以有多个范围键。每个 `hash`+`range` **组合* 必须是唯一的。看看[这个答案](http://stackoverflow.com/a/27348364/627727),看看`hash`和`hash`+`range`的区别。 (2认同)
  • 根据我的经验,您应该这样解释您的条件查询: 1. 获取具有查询中提供的哈希和范围的项目 2. 检查该条目中是否存在属性哈希(或条件中的任何其他属性)。现在显然,如果第一步中没有返回条目,那么在第二步中,每个 attribute_not_exists 返回 true,每个 attribute_exists 返回 false (2认同)

dz9*_*902 11

对于 Google 员工:

  • (a)中attribute_not_exists检查是否与相同的主键的项作为要被插入的项存在
  • (b) 此外,它检查该项目是否存在属性,值无关紧要
  • 如果只想防止覆盖,那么使用attribute_not_existswith主键(或分区键,或范围键),由于键必须存在,check(b)总会通过,只有check(a)有效

推理:

  • 这个名字attribute_not_exists表明它检查是否存在的属性上的项目
  • 但是表中有多个项目,它检查哪个项目
  • 答案是它检查与您放入的具有相同主键的项目
  • 所有条件表达式都会发生这种情况
  • 但与往常一样,它没有得到正确和完整的记录
  • 请参阅下面有关此功能的官方文档,并品尝它的含糊之处

注意:要防止新项目替换现有项目,请使用包含 attribute_not_exists 函数的条件表达式,并将属性名称用作表的分区键。由于每条记录都必须包含该属性,因此 attribute_not_exists 函数仅在不存在匹配项时才会成功。

关联


ioi*_*oio 6

小心保留关键字
attribute_not_exists如果提供的 attributeName 与保留列表中的单词匹配,则将无法按预期工作。hashrange都是保留的,因此需要使用 来解决该问题ExpressionAttributeNames

以下示例允许重复的分区键,并且仅当表中已存在具有提供的分区和排序键的项目时才会失败。

$client->putItem(array(
    'TableName' => 'test',
    'Item' => array(
        'hash' => array('S' => 'abcdefg'),
        'range' => array('S' => 'some other value'),
        'whatever' => array('N' => 233)
    ),
    'ConditionExpression' => 'attribute_not_exists(#h) AND attribute_not_exists(#r)',
    'ExpressionAttributeNames' => array('#h' => 'hash', '#r' => 'range')
));
Run Code Online (Sandbox Code Playgroud)

这将确保指定的分区键hash是唯一的。

 $client->putItem(
     'TableName' => 'test',
     'Item' => array(
        'hash' => array('S' => 'abcdefg'),
        'range' => array('S' => 'some other value'),
        'whatever' => array('N' => 233)
    ),
    'ConditionExpression' => 'attribute_not_exists(#h)',
    'ExpressionAttributeNames' => array('#h' => 'hash')
));
Run Code Online (Sandbox Code Playgroud)