且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-12-02 18:20:34

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

对目前正在发生的事情的一种总结:

  • 一个哈希键可以有多个范围键.
  • 每个项目都有一个 hash 和一个 range
  • 您正在发出 PutItem 请求并且必须同时提供 hashrange
  • 您在 hashrange 属性名称上提供带有 attribute_not_existsConditionExpression
  • attribute_not_exists 条件只是检查具有该名称的属性是否存在,它不关心值

让我们看一个例子.让我们从包含以下数据的 hash+range 键表开始:

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

有四种可能的情况:

  1. 如果您尝试使用 hash=A,range=3attribute_not_exists(hash) 放置项目,则 PutItem将成功,因为 attribute_not_exists(hash) 的计算结果为 true.不存在键 hash=A,range=3 满足 attribute_not_exists(hash) 条件的项.

  2. 如果您尝试使用 hash=A,range=3attribute_not_exists(range) 放置项目,则 PutItem将成功,因为 attribute_not_exists(range) 的计算结果为 true.不存在键 hash=A,range=3 满足 attribute_not_exists(range) 条件的项.

  3. 如果您尝试使用 hash=A,range=1attribute_not_exists(hash) 放置项目,则 PutItem将失败,因为 attribute_not_exists(hash) 的计算结果为 false.存在不满足 attribute_not_exists(hash) 条件的键 hash=A,range=1 的项.

  4. 如果您尝试使用 hash=A,range=1attribute_not_exists(range) 放置项目,则 PutItem将失败,因为 attribute_not_exists(range) 的计算结果为 false.存在不满足 attribute_not_exists(range) 条件的键 hash=A,range=1 的项.

这意味着会发生以下两种情况之一:

  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 键的项目尚不存在,则放置该项目".p>

Here are my use cases: I have a Dynamo table with a hash + range key. When I put new items in the table, I want to do a uniqueness check. Sometimes I want to guarantee that the hash is unique (ignoring the range). Other times I want to allow duplicate hashes, but guarantee that the hash and range combination is unique. How can I accomplish this?

I experimented with attribute_not_exists. It seems to handle the second case, where it checks the hash + key combination. Here's a PHP sample:

$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)'
));

Oddly, it doesn't seem to matter if I use attribute_not_exists(hash) or attribute_not_exists(range). They both seem to do exactly the same thing. Is this how it's supposed to work?

Any idea how to handle the case where I only want to check hash for uniqueness?

You can't. All items in DynamoDB are indexed by either their hash or hash+range (depending on your table).

A sort of summary of what is going on so far:

  • A single hash key can have multiple range keys.
  • Every item has both a hash and a range key
  • You are making a PutItem request and must provide both the hash and range
  • You are providing a ConditionExpression with attribute_not_exists on either the hash or range attribute name
  • The attribute_not_exists condition is merely checking if an attribute with that name exists, it doesn't care about the value

Let's walk through an example. Let's start with a hash+range key table with this data:

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

There are four possible cases:

  1. If you try to put an item with hash=A,range=3 and attribute_not_exists(hash), the PutItem will succeed because attribute_not_exists(hash) evaluates to true. No item exists with key hash=A,range=3 that satisfies the condition of attribute_not_exists(hash).

  2. If you try to put an item with hash=A,range=3 and attribute_not_exists(range), the PutItem will succeed because attribute_not_exists(range) evaluates to true. No item exists with key hash=A,range=3 that satisfies the condition of attribute_not_exists(range).

  3. If you try to put an item with hash=A,range=1 and attribute_not_exists(hash), the PutItem will fail because attribute_not_exists(hash) evaluates to false. An item exists with key hash=A,range=1 that does not satisfy the condition of attribute_not_exists(hash).

  4. If you try to put an item with hash=A,range=1 and attribute_not_exists(range), the PutItem will fail because attribute_not_exists(range) evaluates to false. An item exists with key hash=A,range=1 that does not satisfy the condition of attribute_not_exists(range).

This means that one of two things will happen:

  1. The hash+range pair exists in the database.
    • attribute_not_exists(hash) must be true
    • attribute_not_exists(range) must be true
  2. The hash+range pair does not exist in the database.
    • attribute_not_exists(hash) must be false
    • attribute_not_exists(range) must be false

In both cases, you get the same result regardless of whether you put it on the hash or the range key. The hash+range key identifies a single item in the entire table, and your condition is being evaluated on that item.

You are effectively performing a "put this item if an item with this hash+range key does not already exist".