Amazon Lex and DynamodDB - can't update existing item - amazon-web-services

I'm trying to get a specific item from a table.
My DynamoDB table name is table and I have:
Name PK | Number<br/>
S: Juan | S: #####
When I try to run in Lambda I don't get any Item when it really exist one with that name... any idea why it's like that?
AWS = require("aws-sdk"),
DDB = new AWS.DynamoDB({
region: "REGION",
}),
lookup_name_str = name //From Intent variable,
params = {
TableName: "table",
KeyConditionExpression: "name = :v1",
ExpressionAttributeValues: {
":v1":{
"S": lookup_name_str
}
},
FilterExpression: 'contains(nomColaborador,:v1)',
ProjectionExpression: "Number"
};
console.log(params);
var docClient = new AWS.DynamoDB.DocumentClient();
docClient.scan(params, function(err, data){
if(err){
throw err;
}
if(data.Items && data.Items[0] && data.Items[0].Number){
console.log("There is a Name with that number");
console.log(data.Items[0]);
my_response.statusCode = 200;
my_response.body = {
"sessionAttributes": {
"extension_str": data.Items[0].Number.S,
"nomColaborador": event.currentIntent.slots.Name
},
"dialogAction":{
"type": "Close",
"fulfillmentState": "Fulfilled",
"message": {
"contentType": "PlainText",
"content": data.Items[0].Number.S
}
}
};

The main problem here is that you are doing a scan. KeyConditionExpression isn't a parameter of a scan request. If you are requesting a single item by key you want to use getItem. If you need to query data by partition key and an optional sort key you should use query.
With that all said, when you do a scan, or put a filter on a query, you really need to be sure to page through the data. You will often find that you'll get a response with no data, but a paging key to make another call.

Related

How to append an item to an array in DynamoDB

Hi im trying to append an item to a dynamoDB array.
exports.handler = (event,context,callback)=>{
let params = {
Key:{
"userName":event.userName,
},
UpdateExpression:"set #FutureTrips = list_append(if_not_exists(#FutureTrips,empty_list),country)",
ExpressionAttributeNames:{
"#FutureTrips" : "FutureTrips"
},
ExpressionAttributeValues: {
':country':["Japan"],
":empty_list":[]
},
TableName:"Users"
};
dynamoDB.updateItem(params,function(err,data){
if(err){
console.log(err);
callback(null,err);
}
else{
callback(null,data);
}
});
};
it returns me "message": "Unexpected key '0' found in params.ExpressionAttributeValues[':country']",
im trying to append an item to an array called FutureTrips
thanks for the help
Based on the code you share, currently the UpdateExpression is not referring to the specified ExpressionAttributeValues.
UpdateExpression:"set #FutureTrips = list_append(if_not_exists(#FutureTrips,empty_list),country)"
Correct UpdateExpression should be;
UpdateExpression: "set #FutureTrips = list_append(if_not_exists(#FutureTrips, :empty_list), :country)"

DynamoDB conditional put

Say I want to add a record like below:
{
id:876876,
username:example,
email:xxxxxx#xxx.com,
phone:xxxxxxx,
created_at:current_date,
updated_at:current_date
}
What I want is to check with the id if record exist created_date should not be modified only updated_date should have current_date.
Can we do this with put method without having to be making a get item call?
To create a new item or update an existing item with conditional expression. Prefer to use updateItem rather than putItem.
If the Hash key (Primary key) doesn't exist both putItem and updateItem create a new record. If the record already exist, putItem will completely override the existing row but updateItem only updates the attributes passed in UpdateExpression not a whole record.
In your case, use if_not_exists() function to check whether the created_at field already exists or not. If exists created_at will not be overridden.
Update expression: "SET #email = :email, #created_at = if_not_exists(#created_at, :created_at), #updated_at = :updated_at"
Sample snippet
var params = {
ExpressionAttributeNames: {
"#email": "email",
"#created_at": "created_at",
"#updated_at": "updated_at"
},
ExpressionAttributeValues: {
":email": {
S: "test2#grr.la"
},
":created_at": {
S: date.toISOString()
},
":updated_at": {
S: date.toISOString()
}
},
Key: {
"id": {
S: "T1"
}
},
ReturnValues: "ALL_NEW",
TableName: "stack",
UpdateExpression: "SET #email = :email, #created_at = if_not_exists(#created_at, :created_at), #updated_at = :updated_at"
};
ddb.updateItem(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data);
})

DynamoDB Update - ExpressionAttributeNames can only be specified when using expressions

I need another set of eyes on this. For the life of me I see no issues with this parameter set, used for Dynamo DocumentClient, update method - (here: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#update-property ).
{
TableName: "mygame-dev",
Key: { pk: "09d017aa-cbf7-42ce-be6a-a94ecb58f9a7", sk: "GAME" },
ExpressionAttributeNames: { "#GAMELASTUPDATED": "gameLastUpdated", "#GAMETITLE": "gameTitle" },
ExpressionAttributeValues: { ":gamelastupdated": 1556376010704, ":gametitle": "test title 1" },
UpdateExpression: "SET #GAMELASTUPDATED = :gamelastupdated, #GAMETITLE = :gametitle",
ReturnValues: "ALL_NEW"
};
Error:
ValidationException: ExpressionAttributeNames can only be specified
when using expressions
Any thoughts?
Disregard, this was a copy and paste issue... I was using "query" not "update"
Was:
const updateGameResult = await ddbCall("query", params);
Should have been:
const updateGameResult = await ddbCall("update", params);

Complex Queries in DynamoDB

I am working on an application that uses DynamoDB.
Is there a way where I can create a GSI with multiple attributes. My aim is to query the table with a query of following kind:
(attrA.val1 === someVal1 AND attrB.val2 === someVal2 AND attrC.val3 === someVal3)
OR (attrA.val4 === someVal4 AND attrB.val5 === someVal5 AND attrC.val6 === someVal6)
I am aware we can use Query when we have the Key Attribute and when Key Attribute is unknown we can use Scan operations. I am also aware of GSI if we need to query with non-key attributes. But I need some help in this scenario. Is there a way to model GSI to suit the above query.
I have the below item (i.e. data) on my Movies tables. The below query params works fine for me.
You can add the third attribute as present in the OP. It should work fine.
DynamoDB does support the complex condition on FilterExpression.
Query table based on some condition:-
var table = "Movies";
var year_val = 1991;
var title = "Movie with map attribute";
var params = {
TableName : table,
KeyConditionExpression : 'yearkey = :hkey and title = :rkey',
FilterExpression : '(records.K1 = :k1Val AND records.K2 = :k2Val) OR (records.K3 = :k3Val AND records.K4 = :k4Val)',
ExpressionAttributeValues : {
':hkey' : year_val,
':rkey' : title,
':k3Val' : 'V3',
':k4Val' : 'V4',
':k1Val' : 'V1',
':k2Val' : 'V2'
}
};
docClient.query(params, function(err, data) {
if (err) {
console.error("Unable to read item. Error JSON:", JSON.stringify(err,
null, 2));
} else {
console.log("GetItem succeeded:", JSON.stringify(data, null, 2));
}
});
My Data:-
Result:-
GetItem succeeded: {
"Items": [
{
"title": "Movie with map attribute",
"yearkey": 1991,
"records": {
"K3": "V3",
"K4": "V4",
"K1": "V1",
"K2": "V2"
}
}
],
"Count": 1,
"ScannedCount": 1
}

dynamodb in the browser getting started

I am little confused about retrieving data from dynamodb ... connecting is not an issue cause I am getting The provided key element does not match the schema
:the example provided from AWS
var table = new AWS.DynamoDB({params: {TableName: 'MY_TABLE'}});
var key = 'UNIQUE_KEY_ID';
var itemParams = {Item: {id: {S: key}, data: {S: 'data'}}};
table.getItem({Key: {id: {S: key}}}, function(err, data) {
console.log(data.Item); // print the item data
});
in my case the unique key is "time" and what I want to do is retrieve by key (not unique)
getItem only works on the primary key. From the docs: The GetItem operation returns a set of attributes for the item with the given primary key. See docs.
To solve this, create a Global Secondary Index that has "key" as HASH and "time" as RANGE. Then do a query operation using that index as IndexName:
var params = {
IndexName: 'your-new-GSI-index',
KeyConditionExpression: '#key = :key',
ExpressionAttributeNames: { '#key': 'key },
ExpressionAttributeValues: { ':key': { S: yourKeyVar } }
}
table.query(params, callback);
(did not test this code, but should work)