DynamoDB update map value only if versions match - amazon-dynamodb

I have the following schema:
{
balance: {
customData: string,
version: number
}
}
I need to update balance.customData only if version == 2. Once update operation succeeds, I need to increment version by 1.
I tried the following update transaction
Update: {
Key: {
'pk': pk,
'sk': sk
},
TableName: this.config.getTable(),
UpdateExpression: 'SET #balance.#customData = :customData, #balance.#version = #balance.#version + :incr',
ConditionExpression: '#balance.#customData.#version = :version',
ExpressionAttributeNames: {
'#customData': 'customData',
'#balance': 'balance',
'#version': 'version'
},
ExpressionAttributeValues: {
':customData': balance.customData,
':version': balance.version,
':incr': {'N': 1},
}
}
But when I run this, I get ValidationException: Invalid UpdateExpression: Incorrect operand type for operator or function; operator or function: +, operand type: M
I assume I'm not providing correct syntax to increment map value.
Even if I remove increment part
Update: {
Key: {
'pk': pk,
'sk': sk
},
TableName: this.config.getTable(),
UpdateExpression: 'SET #balance.#customData = :customData,
ConditionExpression: '#balance.#customData.#version = :version',
ExpressionAttributeNames: {
'#customData': 'customData',
'#balance': 'balance',
'#version': 'version'
},
ExpressionAttributeValues: {
':customData': balance.customData,
':version': balance.version
}
}
I still get ValidationError with reason Other, which is not very helpful. Can you please help me understand what I'm doing wrong? Thanks

Related

dynamodb add item to the array list

Using serverless-stack.
I have a table company with multiple branches:
new sst.Table(this, 'Company', {
fields: {
userId: sst.TableFieldType.STRING,
companyId: sst.TableFieldType.STRING,
companyName: sst.TableFieldType.STRING,
branches: [
{
branchId: sst.TableFieldType.STRING,
branchName: sst.TableFieldType.STRING
}
]
},
primaryIndex: {partitionKey: "userId", sortKey: "companyId"}
})
I am trying to add branch to the branches:
const branch = {
branchId: uuid.v1(),
branchName: data.branchName
}
const params = {
TableName: process.env.COMPANY_TABLE_NAME,
Key: {userId: "1", companyId: data.companyId},
UpdateExpression: "ADD #branches :branch",
ExpressionAttributeNames: { "#branches" : "branches" },
ExpressionAttributeValues: { ":branch": [branch] }
}
But I get this error:
ERROR ValidationException: Invalid UpdateExpression: Incorrect operand type for operator or function; operator: ADD, operand type: LIST, typeSet: ALLOWED_FOR_ADD_OPERAND
ValidationException: Invalid UpdateExpression: Incorrect operand type for operator or function; operator: ADD, operand type: LIST, typeSet: ALLOWED_FOR_ADD_OPERAND
ADD is only for numbers and sets. Your branches attribute is a list. So you can use SET with list_append.
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.UpdatingListElements
SET #branches = list_append(#branches, :branch) is correct. But ExpressionAttributeValues should be ExpressionAttributeValues: { ":branch": {"L":[branch]}}
You can refer to https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Client.update_item

Why does Dynamo DB throw an error when updating a map key with the same value?

I am trying to run a simple update query, but got an error when I tried to update the key of a map to the same value. Is there a technical reason this would be disallowed? or some kind of best-practice that I am violating by trying to do this?
Error:
ValidationException: Invalid UpdateExpression: Two document paths overlap with each other;
must remove or rewrite one of these paths; path one: [questions, What is xx?], path two: [questions, What is xx?]
Query object:
{
TableName: 'notesTable',
Key: { topic: 'My tooic' },
ExpressionAttributeNames: { '#qq': 'What is xx?', '#updq': 'What is xx?' },
ExpressionAttributeValues: { ':updans': 'new answer' },
UpdateExpression: 'REMOVE questions.#qq SET questions.#updq = :updans'
}
Multiple ways to deal with scenario when same key needs to be updated. Instead of removing and updating the same key, we can simply SET the key , which replaced the value anyhow.
So, simple way is to send different updateExpression each time.
const qq = "What is xx2?";
const updq = "What is xx?";
let expressionAttributeNames;
let UpdateExpression;
if (qq === updq) {
expressionAttributeNames = { "#updq": "What is xx?" };
UpdateExpression = "SET questions.#updq = :updans";
} else {
expressionAttributeNames = { "#qq": "What is xx1?", "#updq": "What is xx?" };
UpdateExpression = "REMOVE questions.#qq SET questions.#updq = :updans";
}
docClient.update(
{
TableName: "test",
Key: {
id: "My tooic",
},
ExpressionAttributeNames: expressionAttributeNames,
ExpressionAttributeValues: { ":updans": "new answer1" },
UpdateExpression: UpdateExpression,
},
function (error, result) {
console.log("error", error, "result", result);
}
);

Dynamodb - Condition Expression with ExpressionAttributeNames not working

Am trying to do a conditional update and since the field name is a reserved keyword, am using ExpressionAttributeNames to pass in the column name for the condition. The update part isn't working if i use the ExpressionAttributeNames. Any thoughts?
Update: {
Key: {
"pk": "sb#prd#" + productId,
"sk": productId.toString()
},
TableName: 'test',
ConditionExpression: '#minQty >= :minQty',
UpdateExpression: "set sold_count = :sold_count",
ExpressionAttributeNames: {
"#minQty" : "variant[0].items[0].availableQty"
},
ExpressionAttributeValues: {
":sold_count" : 1,
":minQty" : 1
},
}
The aliases defined in ExpressionAttributeNames can only be a single attribute name - they cannot be full paths like variant[0].items[0].availableQty.
You can do something like:
ConditionExpression: '#v[0].#i[0].#a >= :minQty',
ExpressionAttributeNames: {
"#v" : "variant",
"#i" : "items",
"#a" : "availableQty"
},

How to add items to a map in DynamoDB

I'm using the AWS.DynamoDB.DocumentClient with nodejs (lambda functions on AWS)
I've to a db called Translations, primary key Term, sort key Category.
Basically I'm trying to write data in like this:
{
Term: 'hello_there',
Category: 'common_phrases',
Translations: {
en-ca: 'Hello There!'
}
}
and I want to update Translations Map to perhaps add another language, or just modify the en-ca portion of the object.
I've tried the following:
let params = {
TableName: 'Translations',
Key: {
Term: 'hello_there',
Category: 'common_phrases',
},
UpdateExpression:
'SET Translations.#lang = list_append(Translations, :term)',
ExpressionAttributeValues: {
':term': 'french version',
},
ExpressionAttributeNames: {
'#lang': 'fr-ca',
},
}
But I get an error about the wrong operand type.
I've tried:
UpdateExpression:
'SET Translations.#lang = :term',
ExpressionAttributeValues: {
':term': 'french version',
},
ExpressionAttributeNames: {
'#lang': 'fr-ca',
},
But this overwrites the entire contents of the Translations field. Meaning that if I already had en-ca in there, now I would only have fr-ca.
I tried this as well, but also get an operand error:
{
UpdateExpression: 'ADD Translations :term',
ExpressionAttributeValues: {
':term': { 'fr-ff': 'frenchterm' },
},
Any suggestions on how to add/update items to the Translations Map?
Your SET expression was close, try something like this:
UpdateExpression:
'SET #trans.#lang = :term',
ExpressionAttributeValues: {
':term': 'french version',
},
ExpressionAttributeNames: {
'#trans': 'Translations`,
'#lang': 'fr-ca',
},

DynamoDB update error Invalid UpdateExpression: An expression attribute value used in expression is not defined

I am trying to perform an update on DynamoDB table.
The code is (Node.js):
let params = {
TableName: Organizations.Table,
Key: {
'ID': event.ID
},
UpdateExpression: 'SET #OrgName = :org, #Description = :desc',
ExpressionAttributeNames: {
'#OrgName': 'OrgName',
'#Description': 'Description'
},
ExpressionAtributeValues: {
':org': event.OrgName,
':desc': event.Description
},
ReturnValues: 'UPDATED_NEW'
};
this.docClient.update(params, (err, data) => {
if (err) {
return cb(err);
}
return cb(null, data);
});
The event object has all the properties needed.
After executing I get an error:
Invalid UpdateExpression: An expression attribute value used in
expression is not defined; attribute value: :desc
I just followed the examples from DynamoDB docs.
When I change the order of set values, e.g. to SET #Description = :desc, #OrgName = :org the error I get will be about attribute value :org. I also tried to specify expression attribute values explicitly, didn't help.
I can't get what is wrong.
Can someone help me?
There is a spelling mistake in ExpressionAtributeValues (i.e. 't' missing) which is causing the problem.
Please try the below. It should work.
UpdateExpression : "SET #OrgName = :org, #Description = :desc",
ExpressionAttributeNames: {
'#OrgName' : 'OrgName',
'#Description' : 'Description'
},
ExpressionAttributeValues: {':org' : 'new org value',
':desc' : 'new desc value'
},
ReturnValues: 'UPDATED_NEW'

Resources