Home > Software design >  How to apply conditional put on DynamoDB?
How to apply conditional put on DynamoDB?

Time:12-12

I have a dynamoDB table called Cheque to represent a tables' cheque in a restaurant / bar.

I want to apply a conditional put request on this table so that a new table can only be created if the following conditions are meet:

  1. tableNumber does not currently exist AND
  2. restaurnatId does not currently exist AND
  3. isOpen status on the table is false (i.e. cheque is not open)

I am creating my DynamoDB in Terraform like so:

resource "aws_dynamodb_table" "ChequesDDB" {
  name           = "Cheques_${var.env_name}"
  hash_key       = "id"
  billing_mode   = "PROVISIONED"
  read_capacity  = 5
  write_capacity = 5
  stream_enabled   = true
  stream_view_type = "NEW_AND_OLD_IMAGES"
  
  attribute { 
    name = "id"
    type = "S"
  }

  attribute { 
    name = "tableNumber"
    type = "N"
  }

  global_secondary_index {
    name      = "TableNumber"
    hash_key  = "tableNumber"
    write_capacity  = 5
    read_capacity   = 5
    projection_type = "ALL"
  }
}

Note: I am unsure if I need to set my tableNumber as a secondary index but plese let me know if this is not required.

I am then trying to create a new cheque in the DynamoDB table with the following code:

const tableData: Cheque = {
  id: randomUUID(),
  isOpen: true,
  tableNumber: cheque.tableNumber,
  restaurantId: cheque.restaurantId,
  createdAt: new Date().toISOString(),
  updatedAt: new Date().toISOString(),
};

const params: DynamoDB.DocumentClient.PutItemInput = {
  TableName: env.CHEQUE_DDB,
  Item: tableData,
  ConditionExpression: "attribute_not_exists(tableNumber)"
};

await this.db.put(params).promise();

To start with, I am only trying to apply one condition which is to ensure the tableNumber doesn't already exist.

But everytime I run this code, it creates a new entry in the table and I end up with multiple cheques open with table number x.

If I update my conditional expression to be attribute_not_exists(id) then it appears to stop other entries from being opened with the same id. Is this because the id is the primary key?

How can I apply these conditions to fields that are not primary keys and prevent multiple cheques being opened with the same table number?

CodePudding user response:

A conditional check is only placed on a single item, in your case you generate a unique each time so that will always write a new item, as no item will exist fot that unique id.

I would strongly advise against generating a unique id for the partition key, as it's essentially useless to you.

RestaurantId would be a much better key, you can set the sort key as chequeId to ensure items are unique.

Now you can conditionally put an item for a given restaurant/cheque and your conditions will evaluate correctly as you won't be generating a new item each time.

  • Related