AWS Lambda function written in nodejs is not updating my DynamoDB - node.js

I'm a student who is new to AWS, but I have reached a blocker....
I am trying to use a lambda function to update an attribute for an item in my dynamodb table. The lambda function is being triggered, but for some reason I am unable to update the item.
I was able to successfully delete the item from the dynamodb, but when I try to update an attribute for an item nothing happens.
The attribute human_confirmed is not updating to true after the function executes. I've been trying different things I've found on Google, but nothing is working :(
console.log('Loading function');
var AWS = require('aws-sdk');
exports.handler = (event, context, callback) => {
AWS.config.update({
region: "us-east-1"
});
var dynamodb = new AWS.DynamoDB.DocumentClient();
var instance = event.instanceID;
var InstanceName = instance;
var params = {
TableName: "reminders",
Key: {
"instanceID": {
S: InstanceName
},
},
UpdateExpression: 'SET #a = :x',
ExpressionAttributeNames: {'#a' : 'human_confirmed'},
ExpressionAttributeValues: {
':x' : 'true',
},
ReturnValues:"UPDATED_NEW"
};
dynamodb.update(params, function(err, data) {
if (err)
callback(err, null); // an error occurred
else
callback(null, data); // successful response
});
callback(null, "Updating resource from reminder table: " + InstanceName + ".... The system will no longer contain automated emails about this resource's tags!");
};

make sure you have this configuration: dynamodb:PutItem in your serverless.yml file
iamRoleStatements:
- Effect: "Allow"
Action:
- "dynamodb:PutItem"
Resource: "*"

Thanks for the help #kaxi1993
I believe my IAMRole permissions were correct. Here was the code that worked for me.
'use strict';
console.log('Loading function');
var AWS = require('aws-sdk');
var dynamodb = new AWS.DynamoDB({apiVersion: '2012-08-10'});
exports.handler = (event, context, callback) => {
AWS.config.update({
region: 'us-east-1'
});
var instance = event.instanceID;
var params = {
TableName: 'reminders',
Key: {
'instanceID': {
S: instance
}
},
UpdateExpression: 'set human_confirmed = :x',
ExpressionAttributeValues: {
':x': {S: 'true'},
},
ReturnValues: 'UPDATED_NEW'
};
dynamodb.updateItem(params, function(err, data) {
if (err)
callback(err, null); // an error occurred
else
callback(null, data); // successful response
});
callback(null, 'Updating instance from reminder table: ' + instance + '.... The system will no longer contain automated emails about this resource.');
};

Related

DynamoDB Scan with Lambda not returning elements

I have a Lambda with the following code:
// Load the AWS SDK for Node.js.
var AWS = require("aws-sdk");
// Set the AWS Region.
AWS.config.update({ region: "us-east-2" });
exports.handler = function(event, context, callback) {
// Create DynamoDB service object.
var ddb = new AWS.DynamoDB({ apiVersion: "2012-08-10" });
var params = {
TableName: "Ranking",
ProjectionExpression: "#username, Score, Duration",
FilterExpression: "#username = :username",
ExpressionAttributeNames: {
"#username": "Username",
},
ExpressionAttributeValues: {
":username": {
S: 'Alberto'
},
}
};
let toReturn = [];
ddb.scan(params, function (err, data) {
if (err) {
toReturn = err
} else {
toReturn = data.Items;
}
});
let response = {
statusCode: 200,
body: JSON.stringify(toReturn)
};
callback(null, response)
};
However I always see [] as response...
My current DB has the following records:
So my question is... why I don't get back that item?
Since you are using callbacks, your code should be as below. Also Duration is reserved keyword, so it also needs to be modified as below:
// Load the AWS SDK for Node.js.
var AWS = require("aws-sdk");
// Set the AWS Region.
AWS.config.update({ region: "us-east-2" });
exports.handler = function(event, context, callback) {
// Create DynamoDB service object.
var ddb = new AWS.DynamoDB({ apiVersion: "2012-08-10" });
var params = {
TableName: "Ranking",
FilterExpression: "#username = :username",
ProjectionExpression: "#username, Score, #duration",
ExpressionAttributeNames: {
"#username": "Username",
"#duration": "Duration",
},
ExpressionAttributeValues: {
":username": {
S: 'Alberto'
},
}
};
ddb.scan(params, function (err, data) {
if (err) {
callback(null, err)
} else {
callback(null, data.Items)
}
});
};

My Lambda ends before code is complete - node.js

I know this has been asked in various ways before, but I can't figure it out. I'm still very new to node.js and lambda. This code will work if I run the lambda twice, but never runs to completion the first time. This also works fine if I run this from a local IDE by adding
exports.handler();
to the end of the code block.
The code queries DynamoDB for results and then attempts to delete those records from Dynamo. The query part seems to work every time, but the deletion part fails to happen on the first invocation.
I can't seem to figure out what changes are necessary to for lambda to wait until all of my processes are complete.
Thanks in advance.
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set the region
AWS.config.update({ region: 'us-east-2' });
exports.handler = async (event) => {
// Create DynamoDB service object
const ddb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });
const documentClient = new AWS.DynamoDB.DocumentClient({ region: "us-east-2" });
const tablename = process.env.table_name;
let dynapromises = [];
let params = {
ExpressionAttributeValues: {
':offNum': { S: process.env.cost_center },
':s': { N: '2' }
},
ExpressionAttributeNames: {
"#notif_status": "status"
},
KeyConditionExpression: 'officeNumber = :offNum',
TableName: tablename,
IndexName: 'officeNumberIndex',
ProjectionExpression: "notificationNumber",
FilterExpression: '(attribute_not_exists(#notif_status) or #notif_status = :s) and attribute_not_exists(statusTimes)'
};
let qresults = await ddb.query(params).promise();
console.log("Count of notifs again " + qresults.Items.length);
qresults.Items.forEach(function(element, index, array) {
console.log(element.notificationNumber.S);
let delparams = {
TableName: tablename,
ReturnValues: "ALL_OLD",
Key: {
notificationNumber: {
S: element.notificationNumber.S
}
}
};
dynapromises.push(ddb.deleteItem(delparams).promise().then(function(data) {
console.log("Deleted Record:"+ JSON.stringify(data)); // successful response
}, function(error) {
console.log(error, error.stack); // an error occurred
}));
console.log("deletion parameters " + JSON.stringify(delparams));
});
Promise.all(dynapromises).then(res => {
console.log("All promises done");
});
return qresults.Items.length;
};
The issue is in that you are returning before all the promises are completed, you need to move the return qresults.Items.length; inside the last then.
try with this code:
** UPDATE: Change the snippet with the working code **
// Load the AWS SDK for Node.js
const AWS = require('aws-sdk');
// Set the region
AWS.config.update({ region: 'us-east-2' });
exports.handler = async (event) => {
// Create DynamoDB service object
const ddb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });
const documentClient = new AWS.DynamoDB.DocumentClient({ region: "us-east-2" });
const tablename = process.env.table_name;
let params = {
ExpressionAttributeValues: {
':offNum': { S: process.env.cost_center },
':s': { N: '2' }
},
ExpressionAttributeNames: {
"#notif_status": "status"
},
KeyConditionExpression: 'officeNumber = :offNum',
TableName: tablename,
IndexName: 'officeNumberIndex',
ProjectionExpression: "notificationNumber",
FilterExpression: '(attribute_not_exists(#notif_status) or #notif_status = :s) and attribute_not_exists(statusTimes)'
};
let qresults = await ddb.query(params).promise();
console.log("Count of notifs again " + qresults.Items.length);
const dynapromises = qresults.Items.map( async element => {
let delparams = {
TableName: tablename,
ReturnValues: "ALL_OLD",
Key: {
notificationNumber: {
S: element.notificationNumber.S
}
}
};
try {
console.log("deletion parameters " + JSON.stringify(delparams));
const data = await ddb.deleteItem(delparams).promise();
console.log( "Deleted Record:"+ JSON.stringify(data) );
} catch ( err ) {
console.log(error, error.stack); // an error occurred
}
} )
await Promise.all(dynapromises)
console.log("All promises done");
return qresults.Items.length;
};
The code that #pepo posted is performing the Dynamo deletions on the first invocation of the Lambda. Thanks for his work and the responses from everyone.

How do I configure the Amazon DynamoDB region in Nodejs?

I have the following code for adding an item to Amazon DynamoDB . I have set the region to ap-south-1, but the item is getting added to us-east-1 region.
AWS.config.update({
region: "ap-south-1",
endpoint: "dynamodb.ap-south-1.amazonaws.com"
});
var addDocumentToTable = function (tablename, item, callback) {
var docClient = new AWS.DynamoDB.DocumentClient();
var params = {
TableName: tablename,
Item: item
}
docClient.put(params, function (err, data) {
retData = { status: true, message: "Successfully inserted", error: null };
if (err) {
retData.status = false;
retData.message = "Failed to insert into DynamoDB";
retData.error = err;
}
callback(err, retData);
});
}
Adding the details to the DocumentClient has solved it.
var docClient = new AWS.DynamoDB.DocumentClient({ region: Config.AWS.AWS_REGION, endpoint: Config.AWS.ENDPOINT });

Unable to connect to dynammo db from Lambda

I have written a simple lambda function to list the tables on DynammoDb. But When i execute My code, I am unable to connect to the DB server . I am getting NetworkingError .
Below is the Code,
'use strict';
console.log('Loading function');
exports.handler = (event, context, callback) => {
console.log("$$$$$$$$$second test$$$$$$$$$$")
//var src_bkt = event.Records[0].s3.bucket.name;
//var src_key = event.Records[0].s3.object.key;
var AWS = require("aws-sdk");
//console.log(src_bkt)
console.log("##########################################")
console.log("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$")
var dynamodb = new AWS.DynamoDB({
region: 'us-east-1',
endpoint: "http://localhost:8000"
});
dynamodb.listTables({Limit: 10}, function(err, data) {
if (err) {
console.log("Error", err.code);
} else {
console.log("Table names are ", data.TableNames);
}
});
};
Any suggestion will be helpful
You need to create an instance of documentClient like below,
var docClient = new AWS.DynamoDB.DocumentClient();
And call 'listTables' with documentClient. Please find a sample code for PUT which shows how I am using documentClient,
var AWS = require("aws-sdk");
AWS.config.update({
region: "REGION"
});
var docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => {
var table = "EmployeeDetails";
var params = {
TableName: table,
Item: {
"Id" : event.Id,
"FirstName": event.FirstName,
"LastName": event.LastName,
"Age": event.Age,
"Gender": event.Gender
}
};
docClient.put(params, function (err, data) {
if (err) {
console.error("Unable to add item. Error JSON:", JSON.stringify(err, null, 2));
} else {
callback(null, "Added item:", JSON.stringify(data, null, 2))
}
});
};
If you are running in Lambda region is not mandatory but it will work with region as well.
The same code is in my GitHub as well - https://github.com/vnathv/DynamoDb-CRUD.git

Can anyone provide an example of a dynamodb document client upsert?

I'm looking for a non trivial upsert example in node for AWS dynamodb's DocumentClient. Can someone share a sample that has worked for them?
I would like to see an example that sets a created_at, updated_at and a id field on creating the record but only sets the updated_at when the record is found and updated.
This should achieve your goal. My apologies, as I missed your criteria in my original posting. I am assuming id is the key in your table.
'use strict';
var AWS = require('aws-sdk');
var ec2 = new AWS.EC2({ apiVersion: '2016-09-15' });
var ddb = new AWS.DynamoDB.DocumentClient();
AWS.config.region = 'us-east-1';
var ret = {};
const ddbTbl = 'table_name';
var date = new Date();
var dateAsIso = date.toISOString();
exports.handler = (event, context, callback) => {
var key = 'bar';
var params = {
TableName: ddbTbl,
Key: {
"id": key
},
UpdateExpression: "set #u = :t, #c = if_not_exists(#c, :t)",
ExpressionAttributeNames: {
"#u": "updated_at",
"#c": "created_at"
},
ExpressionAttributeValues: {
":t": dateAsIso
},
ReturnValues: "UPDATED_NEW"
};
ddb.update(params, function(err, data) {
if (err) {
console.log(err, err.stack);
ret.ddbUpdate = err;
callback(null, {success: false, message: ["ddb upsert failed"], payload: ret});
// or use the regular callback for failures if you don't want to do your own envelope response
} else {
console.log(data);
ret.ddbUpdate = data;
callback(null, {success: true, message: ["ddb upsert succeeded"], payload: ret});
}
});
};

Resources