Matt
Matt

Reputation: 3890

Can a DynamoDB Condition Expression work on just the Partition Key of a table with a Composite Key

I have a DynamoDB table, with a composite key, which looks like this:

PK SK Type Email Description
USER#A USER#A User [email protected]
USER#A BUG#1 Bug This looks ok
USER#B BUG#2 Bug My user wasn't created first!

I'd like to ensure that a "User" record exists before adding a related "Bug" record - So the 3rd item here is incorrect.

When I put a bug item with the condition attribute_exists(PK), the condition is never true. When I remove the condition, I end up with a that third row; A Bug with no corresponding User.

My understanding is that attribute_exists() only looks at items with the combined composite key, and not across the whole table, regardless of which attribute you supply.

Is there a method of ensuring an item with the same Partition Key exists, while ignoring the Sort Key in this scenario?

Upvotes: 4

Views: 4326

Answers (1)

Seth Geoghegan
Seth Geoghegan

Reputation: 5747

DynamoDB condition expressions can be confusing, and the docs can compound that problem!

The DynamoDB condition expression works by 1) finding the item, 2) evaluating the condition expression, and finally 3) writing to the database if the condition evaluates to true.

I assume your put operation looks something like this:

ddbClient.put({
  TableName: "YOUR TABLE",
  Item: {
    PK: "USER#B",
    SK: "BUG#2",
    Type "Bug",
    Description: "My user wasn't created first!"
  },
  ConditionExpression: "attribute_exists(PK)"
})

In this example, DynamoDB first tries to find the item with PK: "USER#B" SK: "BUG#2", which does not exist. As you're experiencing, this item will not be written to DynamoDB because an item with that primary key does not exist.

The problem you are seeing, as you've alluded to in your question, is that a CondttionExpression applies to only a single item. However, you are trying to conditionally put an item in the database by applying the condition to another item. That is a great candidate for a DynamoDB transaction.

Transactions let you group operations together in an all-or-nothing operation. If one of the operations in your transaction fails, the entire transaction will fail and none of the operations will apply.

You can achieve what you are after by taking this approach

ddbClient.transactWriteItems({
    TransactItems=[
    { "PUT":
        {
          TableName: "YOUR TABLE",
          Item: {
            PK: "USER#B",
            SK: "BUG#2",
            Type "Bug"
          }
        }
    },
    { "ConditionCheck":
        {
          TableName: "YOUR TABLE",
          Item: {
            PK: "USER#B",
            SK: "USER#B"
          },
          ConditionExpression: "attribute_exists(PK)"
        }
    }
  ]

})

In the above transaction, I'm using a ConditionCheck to confirm the existence of a user before entering the bug. If the user does not exist, the transaction will fail and the bug won't be written to DDB.

For a more thorough explanation of DynamoDB Condition Expressions, I highly recommend you check out Understanding DynamoDB Condition Expressions by Alex Debrie.

Upvotes: 6

Related Questions