3

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;
        });
}
NoSQLKnowHow
  • 4,449
  • 23
  • 35
GThree
  • 2,708
  • 7
  • 34
  • 67

2 Answers2

4

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.

Seth Geoghegan
  • 5,372
  • 2
  • 8
  • 23
  • That true for `PutItem` but here I am using `Put`. Here, https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#put-property – GThree Sep 02 '20 at 17:15
  • Hmm, I'm not sure I've ever noticed the difference. The `Put` API says "Creates a new item, or replaces an old item with a new item by delegating to `AWS.DynamoDB.putItem()`". I don't know what your primary key looks like, but perhaps that's what is going on here. DynamoDB thinks you are operating on an old item and delegates to putItem. What behavior are you expecting? I am assuming you are expecting records to be created (not updated) with the `put` operation. Is that assumption correct? – Seth Geoghegan Sep 02 '20 at 18:19
  • Yes. That is the expectation. – GThree Sep 02 '20 at 19:14
  • If you are performing a `put` operation with an item that already exists in DynamoDB, the client is behaving as expected. `put` will create a new item if none with that primary key exists. If the item does exist, it will delegate to `putItem`, which will then completely replace the existing item. Primary keys are unique in DynamoDB, so no two items can have the same primary key. I don't see anything wrong with this code snippet as written. – Seth Geoghegan Sep 02 '20 at 20:22
  • 1
    I figured it out. Here, my primary key was not unique so when combine primary + sortKey then it works. This is new behavior I learned about `Put` today. Thanks for your suggestions. – GThree Sep 02 '20 at 21:18
2

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!

Nacho
  • 119
  • 1
  • 3