How to prevent a DynamoDB item being overwritten if an entry already exists

I see that this question relates to JavaScript language, anyway I will write also for Java (maybe it will be useful for someone):

DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression();
Map<String, ExpectedAttributeValue> expectedAttributes =
        ImmutableMapParameter.<String, ExpectedAttributeValue>builder()
                .put("hashKeyAttrName", new ExpectedAttributeValue(false))
                .put("rangeKeyAttrName", new ExpectedAttributeValue(false))
                .build();
saveExpression.setExpected(expectedAttributes);
saveExpression.setConditionalOperator(ConditionalOperator.AND);

try {
    dynamoDBMapper.save(item, saveExpression);
} catch (ConditionalCheckFailedException e) {
    e.printStackTrace();
}

ConditionalCheckFailedException will be thrown in case we will try to save item with already existing pair of hashKey and rangeKey in DynamoDB.


As an addition to the correct answer of notionquest, the recommended way to express a condition that makes a putItem fail in case the item already exists is to assert that the partition key is not present in any potentially existing item:

"ConditionExpression": "attribute_not_exists(pk)",

This reads "if this item already exists before the putItem, make sure it does not already have a partition key" (pk being the partition key in this example). Since it is impossible for an item to exist without a partition key, this effectively means "make sure this item does not already exist".

See also the "Note" block at the beginning of this page: https://awscli.amazonaws.com/v2/documentation/api/latest/reference/dynamodb/put-item.html

There's an example here when used to guarantee uniqueness of non key columns:

https://aws.amazon.com/blogs/database/simulating-amazon-dynamodb-unique-constraints-using-transactions/


The ConditionExpression can be used to check whether the key attribute values already exists in table and perform the PUT operation only if the key values are not present in the table.

When you run the below code, first time the put operation should be successful. In the second run, the put operation should fail with "Conditional request failed" exception.

My movies table has both partition and sort keys. So, I have used both the attributes in conditional expression.

Sample code with conditional put:-

    var table = "Movies";
    
    var year = 1502;
    var title = "The Big New Movie";
    
    var params = {
        TableName:table,
        Item:{
            "yearkey": year,
            "title": title,
            "info":{
                "plot": "Nothing happens at all.",
                "rating": 0
            }
        },
        ConditionExpression: "yearkey <> :yearKeyVal AND #title <>  :title",
        ExpressionAttributeNames: { 
            "#title" : "title" 
         },
        ExpressionAttributeValues: {
            ":yearKeyVal" : year,
            ":title": {"S": title}
        }
    };
    
    console.log("Adding a new item...");
    docClient.put(params, function(err, data) {
        if (err) {
            console.error("Unable to add item. Error JSON:", JSON.stringify(err, null, 2));
        } else {        
            console.log("Added item:", JSON.stringify(data, null, 2));
        }
    });

Exception when put operation is performed second time:-

Unable to add item. Error JSON: {
  "message": "The conditional request failed",
  "code": "ConditionalCheckFailedException",
  "time": "2017-10-02T18:26:26.093Z",
  "requestId": "7ae3b0c4-3872-478d-908c-94bc9492a43a",
  "statusCode": 400,
  "retryable": false,
  "retryDelay": 0
}