How to check the existing items and prevent unintended overwrites when adding a record in DynamoDB
In this article, we're going to discuss how to check for duplicates when inserting a record in dynamodb.
Let's consider a simple dynamodb table user-jobs
, where userId
is the primary key and you've another attribute jobId
where you store the job id.
You want to prevent multiple jobs from running for the same user. For example, if the user user1
already has a job job1
running - the system should prevent him to create another job.
You can use ConditionExpression
in DynamoDB for achieving the same.
Before discussing ConditionExpression
, let us discuss what would happen if we don't use condition expression.
Below is a simple typescript to create a record in a DynamoDB table
export async function addJob(job: IJob) {
const params: PutItemCommandInput = {
TableName: TABLE_NAME,
Item: marshall(job),
};
const command = new PutItemCommand(params);
const result = await ddbClient.send(command);
console.log("result in addJob:", result);
}
If you execute the below code(which adds 2 jobs - one after the other), the second statement with job2
as jobId
will overwrite the first record in dynamodb.
await addJob({
userId: "user1",
jobId: "job1",
});
await addJob({
userId: "user1",
jobId: "job2",
});
However, you don't want the second record to be inserted as the user already has a job ( job1
) running for him.
In this case, you can use ConditionExpression
, as shown below. The only change to the previous code snippet is that we've added ConditionExpression
property in PutItemCommand input parameters.
We're using attribute_not_exists
condition expression to check whether there is an existing record with the same attribute(userId in our case). If it exists, the operation will fail and the second record will not be inserted.
export async function addJob(job: IJob) {
const params: PutItemCommandInput = {
TableName: TABLE_NAME,
Item: marshall(job),
ConditionExpression: "attribute_not_exists(userId)",
};
const command = new PutItemCommand(params);
const result = await ddbClient.send(command);
console.log("result in addJob:", result);
}
Now, we're going to execute the same set of statements that we used earlier - copied again below for reference
await addJob({
userId: "user1",
jobId: "job1",
});
await addJob({
userId: "user1",
jobId: "job2",
});
The first record will be inserted as there is no job for the user user1
and the second statement will fail with 400
error as shown below
attribute_not_exists
is one of the condition expressions available in dynamodb and below are the different types of condition express that you can use in DynamoDB
attribute_exists()
- Check whether an attribute existsattribute_not_exists()
- Opposite behavior to previous condition expressionattribute_type()
- Check whether an attribute is of a specific typebegins_with()
- Check whether the attribute value begins with a particular substringcontains()
- Check whether a string contains a particular substringsize()
- Check the size of an attribute value. For example, for string attribute - you can use it to check the length of the string.
Please let me know your thoughts in the comments.