how to use node js to combine data from two jsons - node.js

I want to merge data from two tables and then send the result as the response.
I'm new to nodejs and lambda and I'm unable to figure out how I can merge json data from both scan calls and send it as the response.
If I uncomment the callback then response for only one table is sent.
My code is below, can someone please help in completing it
'use strict';
const AWS = require("aws-sdk");
const dynamodb = new AWS.DynamoDB();
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = function(event, ctx, callback) {
var params= {
TableName:'x',
FilterExpression:'SessionId = :SessionId',
ExpressionAttributeValues:{ ":SessionId" : 'ca47a131'},
};
var params1= {
TableName:'y',
FilterExpression:'sessionid = :SessionId',
ExpressionAttributeValues:{ ":SessionId" : 'ca47a131'},
};
docClient.scan(params, onScan);
docClient.scan(params1, onScan1);
function onScan(err, data){
if(err){
callback(err, null);
}else{
//callback(null, data);
}
}
function onScan1(err, data){
if(err){
callback(err, null);
}else{
//callback(null, data);
}
}
}

You can use the following modification to the code so that you can send the response in a single callback.
'use strict';
const AWS = require("aws-sdk");
const dynamodb = new AWS.DynamoDB();
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = function(event, ctx, callback) {
var params= {
TableName:'x',
FilterExpression:'SessionId = :SessionId',
ExpressionAttributeValues:{ ":SessionId" : 'ca47a131'},
};
var params1= {
TableName:'y',
FilterExpression:'sessionid = :SessionId',
ExpressionAttributeValues:{ ":SessionId" : 'ca47a131'},
};
docClient.scan(params, onScan);
docClient.scan(params1, onScan1);
var firstResultData = false;
function runAfterBothCallbacks(data){
if(!firstResultData){
firstResultData = data;
}else{
// Combine firstResultData with data and return in the callback
callback(null,{ dataX: firstResultData, dataY: data });
// Note: The order of scan and scan1 result coming cannot be guaranteed so, dataX can be the results of scan or scan1. If you can identify the result based on the scan, either pass it as another parameter to the runAfterBothCallbacks method or identify the scan based on data result (If possible).
}
}
function onScan(err, data){
if(err){
callback(err, null);
}else{
runAfterBothCallbacks(data);
}
}
function onScan1(err, data){
if(err){
callback(err, null);
}else{
runAfterBothCallbacks(data);
}
}
}

Welcome to JavaScript asynchronous callbacks (aka callback hell).
Fortunately, the AWS SDK supports promises so you can use Promise.all() to wait for multiple promises to be resolved. When that happens, merge the JSON results and return the merged result via the Lambda function's callback() method.

Related

AWS Lambda query with async waterfall in node.js 8.10

I send two query sequentially
Query the data from A tables, and then accoring to the result, query the data from B table.
So, I query the data like that,
var async = require('async');
var mysql = require('mysql');
var config = require('./config.json');
var connection = mysql.createConnection({
host : config.dbhost,
user : config.dbuser,
password : config.dbpassword,
database : config.dbname
});
exports.handler = (event, context, callback) => {
// TODO implement
var tasks = [
function (callback) {
connection.query("SELECT email FROM Visitor WHERE id =?;", [1], function (err, row) {
if (err) return callback(err);
if (row.length == 0) return callback('No Result Error');
callback(null, row[0]);
})
},
function (data, callback) {
connection.query("SELECT id,signtime FROM Board WHERE email =?;", data.email, function (err, row) {
if (err) return callback(err);
if (row.length == 0) {
return callback('No Result Error');
}else {
callback(null, row[0])
}
})
}
];
async.waterfall(tasks, function (err, result) {
if (err)
console.log('err');
else
***return result;***
console.log('done');
connection.end();
});
};
I log the data with console.log(), it take the data in command line.
But in lambda, put the function into exports.handler, it response null.
If I change the 'return result' to callback(result), it occurs error.
I think it maybe too simple to solve this problem
If you know about that, please help me
In the first case, response is null because you didn't use neither Promise, nor callback to let the Lambda sandbox know that the job is done. In the second case, you used the callback, but you passed the result as the first argument to it. Lambda programming model for Node.js follows a principle called "error first callback". Long story short, if any error occurred during execution, you should go with callback(error), and if everything is ok and you need to return some result from lambda, you should go with callback(null, result). So basically on your line before console.log('done'); use callback(null, result) and it will work for you.

How do I chain multiple promises while passing and updating an object through each promise with additional API calls?

I am new to Javascript and am just getting familiar with promises so forgive my ignorance.
What I'm trying to do is request all the records from an Airtable base and filter them them based on a checkbox called "Email Sent" being unsent. When I have the records filtered there are linked records in 2 fields that I need to do additional requests for to get the values for. All of those values (various data, and recipients as an object) then are plugged into an HTML email template and fired off using AWS-SES. Then the "Email Sent" check box is checked for those records to prevent emails from being sent multiple times. The plan is to have this all running on an interval in AWS Lambda. And as records are added to the base they are automatically emailed to a list.
I am able to get the records, and filter them. I am also comfortable with executing the code within Lambda and using SES. But I have been struggling for days to get the values for the linked records. Both of which are lists of people and 1 of which is a recipient email address.
The numerous things I've tried end up either returning the original record called in the first step or returns undefined. I'm chaining a lot of promises and I don't think I'm doing it right because it seems they are running out of order. I'm also at the point of trying weird things like using a global array instead of an object that I'm passing down through the promises and updating.
Any help is appreciated. Thank you in advance.
var Airtable = require('airtable');
var base = new Airtable({apiKey: 'xxxxxxxxxx'}).base('xxxxxxxxxx');
var nodemailer = require("nodemailer")
var handlebars = require('handlebars');
const path = require('path');
var AWS = require("aws-sdk")
var ses = new AWS.SES();
var fs = require('fs');
var mainArray = [];
var readHTMLFile = function(path, callback) {
fs.readFile(path, {encoding: 'utf-8'}, function (err, html) {
if (err) {
throw err;
callback(err);
}
else {
callback(null, html);
}
});
};
function getRecords(){
return new Promise(function(resolve, reject) {
var reqArr = [];
base('Edit Requests').select({
// Selecting the first 3 records in Grid view:
maxRecords: 50,
view: "Grid view"
}).eachPage(function page(records, fetchNextPage) {
// This function (`page`) will get called for each page of records.
records.forEach(function(record) {
// console.log("108: ", record._rawJson.id)
var obj = {}
// obj = record.fields;
// obj.id = record._rawJson.id;
console.log("172", record.fields["Editor Preference"])
obj = record.fields;
obj.id = record._rawJson.id;
if(record.fields["Editor Preference"] != undefined){
obj["Editor Preference"] = obj["Editor Preference"]
// obj["Editor Preference"] = getEditorWrap(record.fields["Editor Preference"])
} else {
obj["Editor Preference"] = "";
}
if(record.fields["Production Manager"] != undefined){
obj["Production Manager"] = obj["Production Manager"]
} else {
obj["Production Manager"] = "";
}
mainArray.push(obj)
// console.log(record.fields["Email"])
// console.log('Retrieved', record.fields['Requested By']);
})
// To fetch the next page of records, call `fetchNextPage`.
// If there are more records, `page` will get called again.
// If there are no more records, `done` will get called.
fetchNextPage();
// console.log("123", reqArr)
// resolve(reqArr)
}, function done(err) {
if (err) { console.error(err); return; }
// console.log("123", mainArray)
resolve(mainArray)
});
// resolve(reqArr)
});
}
function filterRecords(arr){
return new Promise(function(resolve, reject) {
var filtered = []
mainArray = [];
// console.log("245", arr)
for (i in arr){
if(arr[i]['Email Sent'] == undefined){
// console.log("247", arr[i])
mainArray.push(arr[i])
};
}
console.log("filtered: ", mainArray)
resolve(mainArray)
});
}
function setObject(array){
return new Promise(function(resolve, reject) {
for (i in array){
var obj = array[i];
if(obj.id != undefined){
base('Editors').find(obj.id, function(err, record) {
if (err) { console.error(err); return; }
// console.log("281", record.fields);
});
}
}
resolve(mainArray)
});
}
function main1(){
return new Promise(function(resolve, reject) {
getRecords().
then(function(recordArr){
filterRecords(mainArray).
then(function(resultArr){
setObject(mainArray).
then(function(mainArray){
})
})
})
});
}
main1().
then(function(resultArray){
console.log(resultArray)
})

Trying to use AWS lambda to send data to a dynamodb table

console.log('starting function');
var dynamodb = new AWS.DynamoDB();
var AWS = require('aws-sdk');
exports.handler = function (e, ctx, callback) {
var params = {
Item: {
"Name": {
S: "Dalton Warden"
},
"PhoneNumber": {
S: "796-353-1416",
}
},
ReturnConsumedCapacity: "TOTAL",
TableName: "CustomerInfo"
};
dynamodb.putItem(params, function (err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
};
I'm pretty new to lambda and dynamoDB but i'm trying to send data to a table I have set up. I've been through amazon's documentation and looked for similar instances on this site and The formatting looks like it would return the correct JSON but I'm still having trouble. The error I'm getting is Cannot read property 'DynamoDB' of undefined".
Please change the order of the below statements as mentioned below (first AWS and then dynamodb).
var AWS = require('aws-sdk');
var dynamodb = new AWS.DynamoDB();

AWS lambda function retrieving dynamodb data as a error message

I have written simple Lambda function to scan data from dynamodb, but data is getting retrieved with error message tag and lambda function shows message as execution failed
var AWS = require('aws-sdk');
var DOC = require("dynamodb-doc");
var dynamo = new DOC.DynamoDB();
exports.handler = function (event, context, callback) {
var params = {
TableName: "Movies",
// ProjectionExpression: "#yr, Movie",
FilterExpression: "#yr = :thisyear",
ExpressionAttributeNames: {
"#yr": "year",
},
ExpressionAttributeValues: {
":thisyear" : 2009
}
};
dynamo.scan(params, function(err, data){
if (err){
callback("error occoured");
}
else{
callback(JSON.stringify(data.Items));
}
});
};
Result
{
"errorMessage": "[{\"year\":2009,\"Movie\":\"Jab tak hai jaan\"}]"
}
nodejs callback are typically error-first callbacks. It means that the first parameter is the error message and the second parameter is the result. So when returning the result you need to pass null as the first argument.
eg: callback(null, JSON.stringify(data.Items));
Please refer this article

Get Thing Shadow of Aws iot thing in lambda function

I was trying to get the thing shadow of a resource of aws iot in lambda function but the given code is giving null value on success instead of a data. Please let me know where is the problem and what changes should i do to make it work fine. Thanks in advance.
var AWS=require('aws-sdk');
var iotdata = new AWS.IotData({endpoint: 'XXXXXXXXX.iot.us-east-1.amazonaws.com'});
var params = {
thingName: 'thing_name' /* required */
};
exports.handler=function(event,context){
payload1=new Buffer(event.payload);
console.log(payload1);
iotdata.getThingShadow(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
context.succeed(data);
});
};
There are few places which need to be changed. Here is the new code:
getIotShadow: function (thingName) {
config.IOT_BROKER_ENDPOINT = "xxxxxxxxx.iot.us-east-1.amazonaws.com"; // also called the REST API endpoint
config.IOT_BROKER_REGION = "us-east-1"; // eu-west-1 corresponds to the Ireland Region. Use us-east-1 for the N. Virginia region
config.IOT_THING_NAME = thingName;
AWS.config.region = config.IOT_BROKER_REGION;
var iotData = new AWS.IotData({
endpoint: config.IOT_BROKER_ENDPOINT
});
var paramsGet = {
"thingName": config.IOT_THING_NAME /* required */
};
iotData.getThingShadow(paramsGet, function (err, data) {
if (err) {
console.log("Error : " + err, err.stack);
} else {
console.log(JSON.stringify(data));
}
});
}

Resources