'why my condition expression for attribute not exist fails in dynamodb

My DynamoDB table has a primary key as id. The same id will be used to query a record.

Now I want to insert a record with id and originalURL as attributes, I want to insert this record if and only if the id and originalURL doesn't exist in the table.

Update :- ConditionExpression: "attribute_not_exists(id) AND attribute_not_exists(originalURL)" will only works in the context of primary key,according to docs(You can perform a conditional put operation (add a new item if one with the specified primary key doesn't exist) ,so attribute_not_exists(originalURL) is there or not it doesn't make a difference.so i need either a solution where both the conditions work or originalURL also act as a key

router.post('/', async function (req, res, next) {

  urlId = await nanoid(8);


  //const hashids = new Hashids('this is my salt')
  //urlId=hashids.encode(1)
  console.log('jatin', urlId);
  // urlId=uuidv4();

  const { longURL } = req.body

  const params = {
    TableName: 'url',
    Item: {
      "id": urlId,
      "originalURL": longURL
    },
    UpdateExpression: "set originalURL = :y",
    ConditionExpression: "attribute_not_exists(id) AND attribute_not_exists(originalURL)"
  }
  dynamoDb.put(params, (error, data) => {
    if (error) {
      console.log(error);
      res.status(400).json({ error: error });
    } else if (Object.keys(data).length === 0 && data.constructor === Object) {
      res.status(200).json(
        {
          urlId,
          longURL,
          status: 'success'
        })
    }

    else {
      res.status(400).json({ error: 'Please try again' });
    }
  })
});

as of now even if i try to send a request with sam original URL which is already present it successfully adds the record which I don't want.



Solution 1:[1]

For putItem api you can have conditional expressions. According to the Doc

ConditionExpression

A condition that must be satisfied in order for a conditional PutItem operation to succeed.

An expression can contain any of the following:

Functions: attribute_exists | attribute_not_exists | attribute_type | contains | begins_with | size

These function names are case-sensitive.

Comparison operators: = | <> | < | > | <= | >= | BETWEEN | IN

Logical operators: AND | OR | NOT

For more information on condition expressions, see Condition Expressions in the Amazon DynamoDB Developer Guide.

Type: String

Required: No

also the same scenario has been explained in This document: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ConditionExpressions.html#Expressions.ConditionExpressions.PreventingOverwrites

The PutItem operation overwrites an item with the same key (if it exists). If you want to avoid this, use a condition expression. This allows the write to proceed only if the item in question does not already have the same key.

aws dynamodb put-item \
    --table-name ProductCatalog \
    --item file://item.json \
    --condition-expression "attribute_not_exists(Id)" 

Solution 2:[2]

Check if this resolves the problem

import { marshall } from "@aws-sdk/util-dynamodb";

const params = {
    TableName: 'url',
    Item: {
      "id": urlId,
      "originalURL": longURL
    },
    ExpressionAttributeValue: marshal({
       ":originalURL": originalURLVariable
       ":id": idVariable
    }),
    ConditionExpression: "id <> :id AND originalURL <> :originalURL",
    UpdateExpression: "set originalURL = :originalURL",
   }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Aritra Chakraborty
Solution 2 rcnespoli