1

I'm trying to perform a update call to a DynamoDB.DocumentClient instance using AWS SDK with the payload on the code snippet below:

const AWS = require('aws-sdk')
const DynamoDB = new AWS.DynamoDB.DocumentClient()
...

const TableName = 'MyTable'
const Key = { PK: 'MyPK', SK: 'MySK' }
const operation = 'DELETE'
const myId = 'abcde'
const currentRecord = await DynamoDB.get({TableName, Key)

DynamoDB.update({
      TableName,
      Key,
      UpdateExpression: `
        ${operation} myIds :valuesToModify,
        version :incrementVersionBy
      `,
      ConditionExpression: `version = :version`,
      ExpressionAttributeValues: {
        ":version": currentRecord.version,
        ":incrementVersionBy": 1,
        ":valuesToModify": DynamoDB.createSet([myId])
      }
})...

I get this error as result:

ERROR Invoke Error 
{
  "errorType":"Error",
  "errorMessage":"ValidationException: Invalid UpdateExpression: Incorrect operand type for operator or function;
   operator: DELETE, operand type: NUMBER, typeSet: ALLOWED_FOR_DELETE_OPERAND",
  "stack":[...]
}

Interestingly, if operation is changed to ADD it works well.

Any clues that could be helpful to understand why ADD works and not DELETE and/or how to fix and/or yet alternative approaches compatible with this update operation are highly appreciated!

2 Answers 2

2

The only workaround possible here is not to use a DELETE operation, instead, you gotta query the item, find the index in the array you wish to delete, and remove it a REMOVE operation:

like in this case, arrayField contains an array of Users, and I want to delete by user's phoneNumber.

const dataStore = await dynamodb.get(queryParams).promise();
    let i=0; //save the index
    for(i = 0; i < dataStore.Item.myTable.length; i++){
      if(dataStore.Item.arrayField[i].phone === phoneNumber)
      {
        break;
      }
    }
    if(i < dataStore.Item.arrayField.length){
        const updateStoreParams = {
            TableName: tableName,
            Key: storeTableKey,
            UpdateExpression: `REMOVE arrayField[${i}]`,
        }
        await dynamodb.update(updateStoreParams).promise().catch((err) => {
            console.log(err); 
            throw err;
            });
    }
1
  • 1
    thanks for pointing that. I am posting below the actual solution that I've found! Keep Rocking!
    – fagiani
    Commented May 1, 2021 at 19:15
2

It ended up being a semantic error I didn't pay attention to.

When ${operation} was ADD the version field of the UpdateExpression would work because it is a numeric increment.

When ${operation} was DELETE, the version didn't work because, as the error states it was Incorrect operand type for operator or function as it will only work for Removing Elements From a Set as per the docs.

The error was a bit misleading at first but when I tried to implement with other SDK I ended up with the same error then I tried to focus within the UpdateExpression part and found that I had to refactor to something like this in order to it to work:

// Notice below that I inject ADD if operation is DELETE and a comma otherwise
DynamoDB.update({
      TableName,
      Key,
      UpdateExpression: `
        ${operation} socketIds :valuesToModify
        ${operation == 'DELETE' ? 'ADD' : ','} version :incrementVersionBy
      `,
      ConditionExpression: `version = :version`,
      ExpressionAttributeValues: {
        ':version': channelRecord.version,
        ':incrementVersionBy': 1,
        ':valuesToModify': DynamoDB.createSet([socketId])
     }
})

Hopefully it will become useful to others in the future!

1
  • It did ! Thank you very much, I was realy confused with updating Sets of string
    – Shakealot
    Commented Oct 18, 2023 at 10:17

Not the answer you're looking for? Browse other questions tagged or ask your own question.