dynamo db error on update expression using node.js - node.js

i need to update a list on my aws-dynamo database. i have created a table with partition key : email. then iam insert some email id to the table successfully. Now my table like this
email
manaf1#gmail.com
manaf2#gmail.com
manaf3#gmail.com
Then, i tried to update the table with new key "details" and its value is a list. this is my code
var AWS = require("aws-sdk");
var params =
{
TableName: "manaftable1",
Key: { email: "manaf1#gmail.com" },
UpdateExpression: "set #details = list_append (#details, :detailsinput)",
ExpressionAttributeNames: {
"#details": "details"
},
ExpressionAttributeValues: {
":detailsinput":{ "id": "1","mob": "978956" }
}
};
var docClient = new AWS.DynamoDB.DocumentClient();
docClient.update(params, function (err, data) {
if (err)
console.log(JSON.stringify(err, null, 2));
else
console.log(JSON.stringify(data, null, 2));
});
But i got error like this
{
"message": "Invalid UpdateExpression: Incorrect operand type for operator or function; operator or function: list_append, operand type: M",
"code": "ValidationException",
"time": "2016-10-26T11:04:60.756",
"requestId": "SN0NPRHDFHUKBBJHOVI0DFHHRQNSO5AEMVJFFGHF9ASFHUAAJG",
"statusCode": 400,
"retryable": false,
"retryDelay": 0
}
i need response like this after updation
column1 : email
column2 : details
manaf1#gmail.com |
[{"id":"1","mob":"978956"},{"id":"2","mob":"767886"}]
manaf2#gmail.com |
what is the issue related with my code?

As AWS documentation for list_append says:
The new element must be contained in a list, for example to add 2 to a
list, the operand would be [2]
So you need to append an array of objects, not just an object:
var params =
{
TableName: "manaftable1",
Key: { email: "manaf1#gmail.com" },
UpdateExpression: "set #details = list_append (#details, :detailsinput)",
ExpressionAttributeNames: {
"#details": "details"
},
ExpressionAttributeValues: {
":detailsinput": [{ "id": "1","mob": "978956" }]
}
};
If the property does not exist in the object, you can use if_not_exists operand:
var params =
{
TableName: "manaftable1",
Key: { email: "manaf1#gmail.com" },
UpdateExpression: "set if_not_exists(#details, []) set #details = list_append (#details, :detailsinput)",
ExpressionAttributeNames: {
"#details": "details"
},
ExpressionAttributeValues: {
":detailsinput": [{ "id": "1","mob": "978956" }]
}
};

Use list_append() and if_not_exists() together to append to a potentially non-existent list column:
var params = {
TableName: "manaftable1",
Key: { email: "manaf1#gmail.com" },
UpdateExpression: "set #details = list_append(if_not_exists(#details, :empty_list), :detailsinput)",
ExpressionAttributeNames: {
"#details": "details"
},
ExpressionAttributeValues: {
":detailsinput": [{ "id": "1","mob": "978956" }],
":empty_list": []
}
};

When the details attribute is NOT present in the item, the update expression should have just SET without the list_append.
UpdateExpression : "SET #details = :details"
When the details attribute is present in the item and the new update needs to add additional elements in the list, then list_append can be used to add the new element to the list.
UpdateExpression : "set #details = list_append (#details, :details)"

Related

How to set an extra attribute to null in an UpdateExpression in DynamoDB?

I have an update expression like below, which appends a link into the end of a links attribute; but I want to set an extra attribute called twitterLink into NULL in the same UpdateExpression after the append operation is done; can you please help on this?
const params = {
TableName: TABLE_ONE,
Key: {
postId: postId
},
UpdateExpression: "set #links = list_append(if_not_exists(#links, :emptyList), :link",
ExpressionAttributeNames: {
'#links': 'links',
},
ExpressionAttributeValues: {
':link': [link],
':emptyList': []
}
};

Dynamodb UpdateExpression adding new map object to a list of existing Item

I currently have a List attribute in my dynamodb table:
name: "Test User"
recommendations: []
I would like to add new item to the recommendations attribute using the UpdateExpression
const params = {
TableName: 'insiders',
Key:{
"uuid": event.uuid, // WHERE uuid is event.uuid
},
UpdateExpression: "SET #recommendations = :recommendation",
ExpressionAttributeNames: {
"#recommendations": "recommendations",
},
ExpressionAttributeValues: {
":recommendation": [{
"uuid": `ir_${uuidv4()}`,
"recommendation": event.recommendation
}]
},
ReturnValues:"UPDATE_NEW"
};
dynamodb.update(params, function(err, data) { }
I managed to add an object map to recommendations list but when I want to add another one it will replace the object in the recommendation list.
I also tried to use the ADD in UpdateExpression
const params = {
TableName: 'insiders',
Key:{
"uuid": event.uuid,
},
UpdateExpression: "ADD #recommendations :recommendation",
ExpressionAttributeNames: {
"#recommendations": "recommendations",
},
ExpressionAttributeValues: {
":recommendation": [{
"uuid": `ir_${uuidv4()}`,
"recommendation": event.recommendation,
}]
},
ReturnValues:"ALL_NEW"
};
dynamodb.update(params, function(err, data) { }
but Im getting an error
"Invalid UpdateExpression: Incorrect operand type for operator or function; operator: ADD, operand type: LIST",
Okay I already figured out how to add an object to existing map attribute of an item. I used list_append
this will add an object to existing map attribute
const params = {
TableName: 'insiders',
Key:{
"uuid": event.uuid,
},
UpdateExpression: "SET #attrName = list_append(#attrName, :attrValue)",
ExpressionAttributeNames: {
"#attrName": "recommendations",
},
ExpressionAttributeValues: {
":attrValue": [{
"uuid": `ir_${uuidv4()}`,
"recommendation": event.recommendation
}]
},
ReturnValues:"ALL_NEW"
};

Update several attributes only in DynamoDB

Use below codes, I successfully update an item
https://github.com/serverless/examples/blob/master/aws-node-rest-api-with-dynamodb/todos/update.js#L22-L37
const params = {
TableName: process.env.DYNAMODB_TABLE,
Key: {
id: event.pathParameters.id,
},
ExpressionAttributeNames: {
'#todo_text': 'text',
},
ExpressionAttributeValues: {
':text': data.text,
':checked': data.checked,
':updatedAt': timestamp,
},
UpdateExpression: 'SET #todo_text = :text, checked = :checked, updatedAt = :updatedAt',
ReturnValues: 'ALL_NEW',
};
Then I add more attributes:
const params = {
TableName: process.env.DYNAMODB_TABLE,
Key: {
id: event.pathParameters.id,
},
ExpressionAttributeNames: {
'#user_name': 'name',
},
ExpressionAttributeValues: {
':name': data.name,
':email': data.email,
':username': data.username,
':password': data.password,
':checked': data.checked,
':updatedAt': timestamp,
},
UpdateExpression: 'SET #user_name = :name, email = :email, username = :username, password = :password, checked = :checked, updatedAt = :updatedAt',
ReturnValues: 'ALL_NEW',
};
Above codes work fine if I feed all attributes.
$ cat test/user-1.json
{
"name": "Bob",
"email": "bob#example.com",
"username": "bob",
"password": "adfdsfdsf",
"checked": false
}
But if I only want to update part of them, since I needn't update email and password every time, I got error Couldn't fetch the user item.
$ cat test/user-1.json
{
"name": "Bob",
"username": "bob-1",
"checked": false
}
$ curl -X PUT ${url}/${id} --data '#test/user-1.json'
Couldn't fetch the user item.
So how to change the code that I don't have to update all attributes.
The Update API call will not work as the data.email and data.password are undefined.
I would suggest altering the UpdateExpression when you don't need to update those attributes.
I know this is super old, but in case someone else comes across this, I built basically a params factory -- I have a function that returns my params and my ExpressionAttributeValues object and UpdateExpression string only comprise of the variables that pass my validation

node.js passing a parameter to DynamoDB updateItem method

I want to write a function that updates given parameter in dynamodb.
For example in a dynamodb table where each userId is the key I have values like
{
"categoryname": "a",
"skillState": "a",
"skipcount": 1,
"userId": "amzn1.ask.account.xxx”
}
I wanna set the "categoryname": "b" although there might be 10-15 fields like this so I dont wanna hard code the field name.
function (userId,itemToUpdate,itemValue,callback) {
var updateExpressionString = "SET #"+itemToUpdate+" =:val1";
var expressionAtt = '#'+itemToUpdate + '';
console.log(updateExpressionString)
console.log(expressionAtt)
this.dynamodb.updateItem({
TableName: constants.dynamoDBDetailTableName,
Key: {
userId: {
S: userId
}
},
UpdateExpression: updateExpressionString,
ExpressionAttributeNames : {
expressionAtt : itemToUpdate
},
ExpressionAttributeValues : {
':val1': {'S':itemValue}
}
}, function (err, data) {
if (err) {
console.log(err)
console.log('Error ')
} else if (data.Item === undefined) {
}else {
console.log(data)
}
});
}
In ExpressionAttributeNames:
{ ValidationException: ExpressionAttributeNames contains invalid key: Syntax error; key: "expressionAtt"
This throws error obviously thinking that expressionAtt is the key while it is a local variable.
I am new to node.js , how can pass the local variable in to ExpressionAttributeNames and ExpressionAttributeValues
One way of dealing with this could be to pull the object out of updateItem, put it into its own variable like so:
var item = {
TableName: constants.dynamoDBDetailTableName,
Key: {
userId: {
S: userId
}
},
UpdateExpression: updateExpressionString,
ExpressionAttributeNames: {},
ExpressionAttributeValue: {
':val1': {'S': itemValue}
}
};
item.ExpressionAttributeNames[expressionAtt] = itemToUpdate;
this.dynamodb.updateItem(item);
I believe that will fix your problem

How to update an item in Dynamodb of type String Set (SS)?

I have created a attribute of type String Set.
When I create the Item and assign an attribute of type SS everything works.
But when I try to update this attribute, the data type changes to a list ("L").
I try this:
qw = new AWS.DynamoDB.DocumentClient();
var params = {
TableName : "myTable",
Key: {
"id": somekey
},
UpdateExpression: "set ssvar= :arrp",
ExpressionAttributeValues: {
":arrp": [ "test", "test2" ]
}
};
qw.update (etc.)
This leads to a change in datatype in dynamodb and in stead of a string set I get a list:
"ssvar": {
"L": [
{
"S": "test"
},
{
"S": "test2"
}
]
}
I have tried all kinds of solutions like below but always my datatype gets changed.
ExpressionAttributeValues: {
":arrp":
"SS": [ "test", "test2" ]
}
How can I update an attribute of type string set?
As of September 2015, there is a createSet function in the DocumentClient that you can use for this.
UPDATE - added example
I've modified your example code to use this function:
qw = new AWS.DynamoDB.DocumentClient();
var params = {
TableName : "myTable",
Key: {
"id": somekey
},
UpdateExpression: "set ssvar= :arrp",
ExpressionAttributeValues: {
":arrp": qw.createSet([ "test", "test2" ])
}
};
qw.update (etc.)
This is an artifact of using the DocumentClient - StringSet is not a JSON type.
The DocumentClient converts a StringSet to the Array native JavaScript type:
https://github.com/aws/aws-sdk-js/blob/master/lib/dynamodb/converter.js#L61. Then the client serializes the native JavaScript Array as a DynamoDB List type: https://github.com/aws/aws-sdk-js/blob/master/lib/dynamodb/converter.js#L12.
If you want to use the StringSet type, you can use the low-level API: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html
An alternative simpler syntax
Upsert Item and Add "A" to set
const documentClient = new AWS.DynamoDB.DocumentClient();
await documentClient.update({
TableName,
Key: { hashKey, sortKey },
AttributeUpdates: {
'userIDs': {
Action: 'ADD',
Value: documentClient.createSet(['A' ])
},
},
}).promise();
Upsert Item and remove "A" from set
await documentClient.update({
TableName,
Key: { hashKey, sortKey },
AttributeUpdates: {
'userIDs': {
Action: 'DELTE',
Value: documentClient.createSet(['A'])
},
},
}).promise();
Update expression docs
documentClient.createSet
documentClient.update

Resources