how to access result outside the loop - node.js

i am not able to access variable outside the SearchData.forEach loop here is my code
SearchDataJson =[];
var searchdataArray = [];
SearchData.forEach( async function(item){
var sql = "SELECT email , mobile from user_profile where id in (228,192) limit 2";
var tempData = function() {
return new Promise(function (resolve, reject) {
pool.query(sql, function (err, results, fields) {
if (err) return reject(err);
return resolve(results);
});
});
};
await tempData().then( async function(results) {
SearchDataJson.push({KeyTags:item.hashtags,Data:results});
});
console.log(SearchDataJson);
});

Related

promise all not working as expected while working with list

I want the callback to return the response when promise all finishes. I am getting the response before promise all. Batch List is empty in response, as it is returned before promise all.
getByReferenceID(object, mode, limit, lastEvaluatedKey, callback){
var results = {};
var requestList = [];
var batchList = [];
var response = {};
new Promise((resolve, reject) => {
this.getRequestList(object, limit, lastEvaluatedKey,function (err, result) {
console.log(result);
results = result;
if(err) {
reject();
} else {
resolve();
}
});
}).then(async () =>
{
requestList = requestList.concat(results.items);
const runAsyncFunctions = async () => {
var promises = [];
requestList.map(async request => {
var promise = await this.getBatchList(request.requestID.S, mode, null, null, function(err, result) {
batchList = batchList.concat(result.items);
});
promises.concat(promise);
});
await Promise.all(
promises
).then(()=>{
response = {
"requests": requestList,
"batches": batchList,
"lastEvaluatedKey": results.LastEvaluatedKey
};
callback("", response);
}).catch((error) => {
console.log(error);
});
};
await runAsyncFunctions();
}).catch((error) => {
callback(error, response);
});
}
promises is not an array of promises.
The line
var promise = await this.getBatchList(request.requestID.S, mode, null, null, function(err, result) {
batchList = batchList.concat(result.items);
});
is executed later then
callback("", response)
I guess you want to do something like this
var promises = [];
for (const request of requestList) {
const promise = this.getBatchList(request.requestID.S, mode, null, null, function (err, result) {
batchList = batchList.concat(result.items);
});
promises.push(promise);
}
await Promise.all(
...
The correct way of doing it is:
getByReferenceID(object, mode, limit, lastEvaluatedKey, callback){
var results = {};
var requestList = [];
var batchList = [];
var response = {};
new Promise((resolve, reject) => {
this.getRequestList(object, limit, lastEvaluatedKey,function (err, result) {
console.log(result);
results = result;
if(err){
reject(err);
}
else{
resolve();
}
});
return results;
}).then(() =>
{
requestList = requestList.concat(results.items);
var iteration =0;
new Promise((resolve, reject) => {
for (let request of requestList) {
console.log(request.requestID.S);
this.getBatchList(request.requestID.S, mode, null, null, function (err, result) {
iteration++;
batchList = batchList.concat(result.items);
if(iteration === requestList.length)
{
resolve();
}
if(err)
{
reject();
}
});
}
}).then(()=>{
response = {
"requests": requestList,
"batches": batchList,
"lastEvaluatedKey": results.LastEvaluatedKey,
};
callback("", response);
}).catch((error) => {
callback(error, response);
});
}).catch((error) => {
callback(error, response);
});
}

resolving a promise using mongodb and nodejs

Hello I am new to nodejs and mongodb, i am having trouble resolving my first promise after the second promise has been resolved. I can see the result of my second promise after it is resolved. Here is my code
var getShows = function () {
return new Promise(function (resolve, reject) {
usersdb.find(function (err, result) {
if(err) return console.error(err);
var usersFromCall = result;
var task = function (users) {
return new Promise(function (resolve, reject) {
var user = {
'name': '',
'pages': []
}
user.name = users.show;
console.log(users);
pagedb.find({'show' : user.name}, function (err, resp) {
for(var j = 0 ; j <resp.length; j ++){
var pages = { 'pageId': ''};
pages.pageId = resp[j].pageId;
user.pages.push(pages);
}
console.log(user);
resolve({show: user});
})
});
};
var actions = usersFromCall.map(task);
return Promise.all(actions);
}).then(function () {
resolve()
})
});
};
do i resolve the first promise in a then function after the find?
The following should work:
var getShows = function () {
return new Promise(function (resolve, reject) {
usersdb.find(function (err, users) {
if (err) return console.error(err);
var task = function (user) {
return new Promise(/* ... */);
};
var actions = users.map(task);
Promise.all(actions).then(resolve, reject);
});
});
};
getShows().then(function (results) {
// Prints the result of each task as an array
console.log(results);
});
Looking at your code, it seems .find returns a Promise. So, just for the sake of avoiding the Promise constructor anti-pattern please try the following, I believe it will produce the correct result
var getShows = function() {
return usersdb.find()
.then(result =>
Promise.all(result.map(
users =>
pagedb.find({
show: users.show
})
.then(resp => ({
show: {
name: users.show,
pages: resp.map(item => ({pageId: item.pageId}))
}
}))
)
)
);
};
or the ES5 version
var getShows = function getShows() {
return usersdb.find().then(function (result) {
return Promise.all(result.map(function (users) {
return pagedb.find({
show: users.show
}).then(function (resp) {
return {
show: {
name: users.show,
pages: resp.map(function (item) {
return { pageId: item.pageId };
})
}
};
});
}));
});
};

Node js send an email with pdf as attachement synchronously

Task : Get query from database => generate multiple pdf => send in mail attachment via node js
Problem: the problem here is before pdfs are generated my sendMail() function called. So how to call sendMail function only after all pdfs generated?
pdfs = [];
// Pdf generate code
var generatePdf = function (rows) {
return new Promise(function (resolve, reject) {
for (var i = 0; i < rows.length; i++) {
html = ejs.renderFile(
'views/voucher.ejs',
{
voucher: rows[i]
},
function (error, success) {
if (error) {
console.log(error);
} else {
var pdf_path = '/srv/ voucher/uploads/voucher/' + Math.random().toString(36).substring(7) + '.pdf';
htmlToPdf.convertHTMLString(success, pdf_path, function (error, success) {
if (error) {
console.log('Oh noes! Errorz!');
console.log(error);
} else {
pdfs.push(pdf_path);
console.log("Single");
console.log(pdfs);
console.log('Woot! Success!');
}
});
}
});
}
resolve();
});
}
// send mail code
var sendMail = function () {
new Promise(function (resolve, reject) {
console.log("All" + pdfs);
pdfs.forEach(function (value, key) {
// mail sending code
});
});
};
var findVoucherAndSendMail = function () {
return new Promise(function (resolve, reject) {
var query = con.query('SELECT * FROM voucher limit 20', function selectAll(err, rows, fields) {
if (err) {
throw err;
}
resolve(rows);
});
});
};
findVoucherAndSendMail().then(function (fromResolve) {
return generatePdf(fromResolve);
}).then(function () {
return sendMail();
}).catch(function () {
});
Your problem is link to an asynchronous behavior in your for loop when generating pdf.
Your promise is resolved before your pdfs are generated.
You should use Promise.all to wait for generation completion.
function generatePdf(rows) {
return Promise.all(rows.map(row => asyncPdfGeneration(row));
}
function asyncPdfGeneration(row) {
return new Promise(function (resolve, reject) {
...generate pdf
resolve(pdf);
}
}
The 2nd 'then' is on your function findVoucherAndSendMail(), so both generatePdf() and sendMail() will fire once findVoucherAndSendMail() is finished.
Place the 2nd 'then' on generatePdf()
findVoucherAndSendMail().then(function (fromResolve) {
return generatePdf(fromResolve).then(function () {
return sendMail();
});
}).catch(function () {
});
edit
Did you try: resolve(pdfs); instead of just resolve();

MongoDB custom wrapper code check: Am I writing ok code?

I'm wondering if the code I have written here is sane and follows the rule of non-blocking, I come from a Java background so I'm new to non-blocking event loop of Node.js.
retard.js:
var MongoClient = require('mongodb').MongoClient;
var retard = {};
retard.getDb = function (url) { // url example 'mongodb://localhost:27017/myproject'
return new Promise(function (resolve, reject) {
MongoClient.connect(url, function (err, db) {
if (err)
throw err;
// custom functions
db.getCollection = function (mCollection) {
var obj = {};
var collection = db.collection(mCollection);
// access to the native drivers
obj.native = collection;
obj.findOne = function (query) {
return new Promise(function (resolve, reject) {
collection.findOne(query, function (err, result) {
if (err)
throw err;
resolve(result);
});
});
};
return obj;
};
resolve(db);
});
});
};
module.exports = retard;
This would then be used as following:
var co = require('co');
var config = require('./config');
var retard = require('./lib/retard');
co(function* () {
var db =
yield retard.getDb(config.mongodb.url);
var countries = db.getCollection('countries');
// first query
var doc =
yield countries.findOne({
country: 'scotland'
});
console.log(JSON.stringify(doc));
// second query
countries.native.findOne({
country: 'scotland'
}, function (err, result) {
if (err)
throw err;
console.log(JSON.stringify(result));
});
});
I get the results I was expecting from the database so it works. I'm just curious as to is this ok JavaScripting?
Almost there! Something to keep in mind is that that mongodb driver methods already return a Promise if no callback is passed (findone).
Rather than wrapping the methods with a new Promise, you can just return the method itself (a Promise) as follows:
return collection.findOne(query)
as opposed to:
return new Promise(function (resolve, reject) {
collection.findOne(query, function (err, result) {
if (err)
throw err;
resolve(result);
});
});
Same applies to MongoClient.connect();

Bluebird promises in Node.js

In the below code I need to call function1() and then function2().
Both functions do some asynchronous operations in it. So I wanted it to be called one after the other.
There is a mysql connection object that will be returned as a promise. So it has to be used in entire program finally closed at the end.
When I run the below code I don't get output it just stays blank and trying to debug it never hits function1.
constants.js
var Promise = require('bluebird');
module.exports = {
getMySqlConnection: function () {
var conObj = { host: "localhost", user: "root", password: "", database: "deccan" };
var connection = require("mysql").createConnection(conObj);
return new Promise(function (resolve, reject) {
connection.connect(function (error) {
if (error)
reject(error);
else
resolve(connection);
});
});
}
};
testing.js
var constants = require("./constants.js");
var Promise = require('bluebird');
var mysqlConnection = null;
constants.getMySqlConnection().then(function (connection)
{
mysqlConnection = connection;
return new Promise(function1);
})
.catch(function (e)
{
console.log(e);
}).then(function (result)
{
console.log("Finished Everything");
});
function function1()
{
return new Promise(function (resolve, reject)
{
var sql = "select *from employee";
mysqlConnection.query(sql, function (error, results)
{
if (error)
reject(error);
else
resolve(results);
});
}).then(function (value)
{
return new Promise(function (resolve, reject)
{
// do something here
});
});
}
function function2()
{
return new Promise(function (resolve, reject)
{
var sql = "select *from management";
mysqlConnection.query(sql, function (error, results)
{
if (error)
reject(error);
else
resolve(results);
});
}).then(function (value)
{
return new Promise(function (resolve, reject)
{
// do something here
});
});
}

Resources