Why "documentClient.put" is doing UPDATE instead of INSERT in DynamoDB?

Viewed 2318

I have a simple logic where I want to INSERT record in the table using AWS.DynamoDB.DocumentClient. Below is code which I am using. Here, I am noticing that .put is updating the record and not sure why.

While checking the logs in CW, I am not seeing any error so not sure what am I missing here.

Code:

async addEvent(incomingModel: MyModel): Promise <MyModel> {
    const dynamoModel: MyModel = {
        fieldOne: incomingModel.fieldOne,
        fieldTwo: incomingModel.fieldTwo,
        "One#two#three": `${incomingModel.one}#${incomingModel.two}#${incomingModel.three}`,
        fieldThree: incomingModel.fieldThree,
        fieldFour: incomingModel.fieldFour,
    };

    var params = {
        TableName: 'Table',
        Item: dynamoModel,
    };

    return this.documentClient
        .put(params)
        .then((data) => {
            this.logger.debug(
                "Response received from Dynamo after adding an incomingModel",
                data,
                this.constructor.name,
            );

            return data as MyModel;
        })
        .catch((error) => {
            const errorMessage = JSON.stringify(error);
            this.logger.error(
                `Error creating incomingModel with body of ${errorMessage}`,
                error,
                this.constructor.name,
            );
            throw error;
        });
}
2 Answers

This is the expected behavior of the put operation. From the docs (emphasis mine):

Creates a new item, or replaces an old item with a new item. If an item that has the same primary key as the new item already exists in the specified table, the new item completely replaces the existing item.

As Seth mentioned, this is the default behaviour of DynamoDb.

What you can do to avoid updates is make use of the "ConditionExpression". Here in my example, I named 'PK' to the HashKey and 'SK' to the RangeKey:

async function put(Item, TableName){
    const params = {
        TableName,
        Item,
        ExpressionAttributeNames : {
            '#pk' : 'PK',
            '#sk' : 'SK',
        },
        ConditionExpression : 'attribute_not_exists(#pk) AND attribute_not_exists(#sk)',
    };
    
    const result = await documentClient.put(params).promise();
    
    // ... do the rest....

}

If the item already exist (Both keys matches) the transaction will fail giving a "ConditionalCheckFailedException: The conditional request failed"

I hope this will be useful!

Related