0

I would like PutItem to succeed only if the GSI partition key for the new item already exists on another item.

Suppose my table has these items (omitting some attributes):

PK       GSI1PK    GSI1SK
1        a         b
2        c         d

And I am attempting to put this item:

{
  PK: 3,
  GSI1PK: "e",
  GSI1SK: "f"
}

I want this PutItem request to fail, since the table does not yet contain an item with GSI1PK == "e".

I'd like to solve this with a condition expression if possible. I would not like to solve this by querying the table before the PutItem request.

Here is how I have attempted this with an example (go sdk) that I would like to succeed:

input := &dynamodb.PutItemInput{
    Item: map[string]*dynamodb.AttributeValue{
        "PK":         intAttrVal(3),
        "GSI1PK":     stringAttrVal("a"),
        "GSI1SK":     stringAttrVal("f"),
    },
    ConditionExpression: stringRef("attribute_exists(GSI1PK)"),
    TableName:           &tableName,
}

But and exception is thrown: "ConditionalCheckFailedException: The conditional request failed".

twharmon
  • 4,153
  • 5
  • 22
  • 48
  • In your example of put request you want to fail, you mention "...the table does not yet contain an item with GSI1PK == "d", yet the item has "GSI1PK: "e"". Is this correct? – Perttu Haliseva Oct 21 '20 at 14:10
  • @PerttuHaliseva That was a typo. I fixed it. – twharmon Oct 21 '20 at 14:12
  • From what I see, this might not be possible. Here's a related answer which explains the issue better than I can: https://stackoverflow.com/questions/32833351/dynamodb-put-item-if-hash-or-hash-and-range-combination-doesnt-exist – Perttu Haliseva Oct 21 '20 at 15:19

1 Answers1

1

I do not really see a way to do this since the value you want to check is on another item. Therefore, put the two operations a ConditionCheck and PutItem in a DynamoDB transaction. If the conditional check, which checks if the value in the other item exists, and the PutItem succeed, then you're good. If the conditional check fails, so does the PutItem.

NoSQLKnowHow
  • 4,449
  • 23
  • 35
  • For now I am doing that, but without the transaction. Thanks. Will accept your answer if no one offers a way to do it in on PutItem request. – twharmon Oct 21 '20 at 21:04
  • 1
    At least with the transaction, you are not doing round trips to the DB. it is all in one trip. – NoSQLKnowHow Oct 21 '20 at 21:06
  • 1
    Doing a `GetItem` and `PutItem` operations in the same transaction is not supported. However, I believe this is the right direction. You could to a `ConditionCheck` followed by a `Put`. https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-example.html – Perttu Haliseva Oct 22 '20 at 07:01
  • Good catch. Not sure why I was stuck on getitem. You are correct, it is ConditionCheck, not a GetItem. I changed my answer to say this correctly. – NoSQLKnowHow Oct 22 '20 at 17:23
  • Can I do a `ConditionCheck` with GSI? I think it requires the primary key. – twharmon Oct 22 '20 at 17:43