Setting up a promise in Node Js - node.js

I am having trouble setting up my promise in my code. This is what I have implemented right now:
let promise = new Promise(function(resolve, reject){
ATVStatement();
let isdone = true;
if(isdone){
resolve();
}else{
reject();
}
})
promise.then(CustomMessage());
The problem I am getting is that the I pretty sure that the promise is not working. If anyone could spot the error that I am doing I would greatly appreciate it.
EDIT
Here is code for the the two functions being used:
function ATVStatement() {
request = new Request("select distinct(\"Product Name\") from SPA_Data_Feeds where \"Strategic Priority\" = 'Accelerate to Value (LD)'",
function(err, rowCount, rows)
{
console.log(rowCount + ' row(s) returned');
}
);
//var result = "";
var count = 0
request.on('row', function(columns) {
columns.forEach(function(column) {
console.log("%s\t", column.value);
result+= column.value + "\t\n"; //result is a global variable
count++;
});
});
connection.execSql(request);
}
function CustomMessage(){
console.log('here')
var customMessage = new builder.Message(session)
.text("### Here is a list of the ATV Compounds: \n" + "> %s ", result)
.textFormat("markdown")
.speak("Here is what I found for \'%s\'.", session.message.text)
.textLocale("en-us");
session.send(customMessage); }

Ok, so now we understand the code a little better (thanks for updating), we need to modify the ATVStatement to return a promise and resolve it when the query is complete.
We change the code above to:
let atvPromise = ATVStatement();
atvPromise.then ((result) => {
CustomMessage();
}).catch ( (err) => {
console.log('An error occurred: ' + err);
});
function ATVStatement() {
return new Promise(function(resolve, reject) {
request = new Request("select distinct(\"Product Name\") from SPA_Data_Feeds where \"Strategic Priority\" = 'Accelerate to Value (LD)'",
function(err, rowCount, rows)
{
console.log(rowCount + ' row(s) returned');
if (err) {
reject(err);
} else {
resolve(rows);
}
}
);
var count = 0
request.on('row', function(columns) {
columns.forEach(function(column) {
console.log("%s\t", column.value);
result+= column.value + "\t\n"; //result is a global variable
count++;
});
});
connection.execSql(request);
});
}
You see, ATVStatement was actually asynchronous.

Related

Return undefined value outside the loop

I'm using a for loop for checking the queries I've read before, and after I adding the wrong queries to a map and return the map I received 'undefined'.
I'm using async functions but it didn't help.
This is the function:
async function validateQueryResult(connection, queries) {
var result;
var alertsList = new Map();
return new Promise((resolve, reject) => {
for (query in queries) {
connection.execute({
sqlText: queries[query]["query"],
complete: function (err, stmt, rows) {
if (err) {
console.error('Failed to execute query ' + queries[query]["query"] + ' due to the following error: ' + err.message);
}
else {
rows[0].toString();
result = Object.values(rows[0]);
if (result[0] > 0) {
alertsList.set(queries[query], result[0]);
}
}
}
});
}
resolve(alertsList);
})
}
Thanks for help!
Your problem is, that connection.execute() is another async call. And your for-loop is done before any of the expected answers returns. Try it this way:
async function validateQueryResult(connection, queries) {
var result;
var alertsList = new Map();
return new Promise((resolve, reject) => {
for (query in queries) {
const result = await this.execute(query);
if (result && result[0] > 0) {
alertsList.set(queries[query], result[0]);
}
}
resolve(alertsList);
})
}
async function execute(query) {
connection.execute({
sqlText: queries[query]["query"],
complete: function (err, stmt, rows) {
if (err) {
console.error('Failed to execute query ' + queries[query]["query"] + ' due to the following error: ' + err.message);
}
else {
rows[0].toString();
return Object.values(rows[0]);
}
}
});
}

How to promise in a nested Asynchronous operations

I've been struggling to figure out how to do this for the past two hours. But I can't seem to get the Promise to wait for my searchFacesFunc to complete before it solves. What is the correct way to do so?
async function searchFacesFunc(faceId){
var searchFacesParams = {
CollectionId: "my-collection",
FaceId: faceId,
FaceMatchThreshold: 80,
MaxFaces: 10
};
await rekognition.searchFaces(searchFacesParams, function(err, data) {
if(err){
throw err;
}else{
var matching_percent = data.FaceMatches[0].Similarity;
console.log('Matching Percent: ' + matching_percent);
}
});
}
return new Promise((resolve, reject) => {
rekognition.indexFaces(indexParams, function(err, data) {
if(err){
throw err;
}else{
const faceRecords = data.FaceRecords;
for(let i = 0; i < faceRecords.length; i++){
var faceId = faceRecords[i].Face.FaceId;
console.log('FaceId: ' + faceId);
searchFacesFunc(faceId); //The promise is finished before these multiple functions finish
}
resolve(null, 'success');
}
});
});
If the rekognition.indexFaces function accepts an asynchronous callback, you can solve this issue easily:
return rekognition.indexFaces(indexParams, async (err, data) => {
if (err) {
throw err;
} else {
const faceRecords = data.FaceRecords;
for (let i = 0; i < faceRecords.length; i++) {
var faceId = faceRecords[i].Face.FaceId;
console.log("FaceId: " + faceId);
await searchFacesFunc(faceId); // Await the promise
}
return "success";
}
});
};
However, if this is not the case, you can still solve this the following way:
Use util.promisify to "promisify" the rekognition.indexFaces function
Construct a recursive callback function that only resolves the original promise you constructed when it executed faceRecords.length times.

Boolean not set to true node.js

I have this code:
at the beginning of the file I initialized the variable (var loginState = false;)
Why console.log give me false, although I change it to true
try {
const client = new SimpleGraphClient(tokenResponse.token);
const me = await client.getMe();
sql.connect(config, async function (err){
if (err) console.log(err);
var request = new sql.Request();
request.query(`SELECT * FROM tradebot.accounts WHERE username='${username}' AND password='${password}'`, async function (err, recordset){
if (err) console.log(err);
console.log(recordset);
if (recordset.recordset.length == 1) {
loginState = true;
} else {
loginState = false;
}
sql.close();
});
});
console.log(loginState);
if (loginState == true) {
await turnContext.sendActivity({
text: 'Work',
attachments: [CardFactory.adaptiveCard(mainmenu)]
});
} else {
await turnContext.sendActivity({
text: 'Dont work',
attachments: [CardFactory.adaptiveCard(internal_login)]
});
}
} catch (error) {
throw error;
}
Put that console.log() inside sql.connect()`, it works the way you are expecting.
sql.connect() is an asynchronous method, so by the time the console.log() happens the sql.connect() doesn't have changed the variable value yet.
loginState = false; // Statement 1
sql.connect(config, async function (err) { // Statement 2
loginState = true;
})
console.log(loginState); // Statement 3
The order of execution of above will be,
Statement 1
Statement 3
Statement 2
So that's why it happens.
Change the code as follows for it to work fine.
try {
const client = new SimpleGraphClient(tokenResponse.token);
const me = await client.getMe();
sql.connect(config, async function (err) {
if (err) console.log(err);
var request = new sql.Request();
request.query(`SELECT * FROM tradebot.accounts WHERE username='${username}' AND password='${password}'`, async function (err, recordset) {
if (err) console.log(err);
console.log(recordset);
if (recordset.recordset.length == 1) {
await turnContext.sendActivity({
text: 'Work',
attachments: [CardFactory.adaptiveCard(mainmenu)]
});
} else {
await turnContext.sendActivity({
text: 'Dont work',
attachments: [CardFactory.adaptiveCard(internal_login)]
});
}
sql.close();
});
});
} catch (error) {
throw error;
}
Hope this helps!
The reason is because you are setting the value to variable inside a callback function :
You have to await your query result. The way you are calling the query is not feasible.
Take a look at - https://www.npmjs.com/package/mysql2
Also change this part -
sql.connect(config, async function (err){
if (err) console.log(err);
var request = new sql.Request();
request.query(`SELECT * FROM tradebot.accounts WHERE username='${username}' AND password='${password}'`, async function (err, recordset){
if (err) console.log(err);
console.log(recordset);
if (recordset.recordset.length == 1) {
loginState = true;
} else {
loginState = false;
}
sql.close();
});
});
Change this to something like this :
try{
let connection = await sql.connect(config);
let query1 = await connection.query(`SELECT * FROM tradebot.accounts WHERE username='${username}' AND password='${password}'`);
if (query1[0].recordset.length == 1) {
loginState = true;
} else {
loginState = false;
}
}catch (err){
// do something here
}

Nodejs return Asynchronously result as an array

in my server application i have some method such as:
insert message when user joined to application(insertUserJoinedMessageAndSendMessage)
get unique id of owner mobile numbers (getOwnerPhoneNumberUniqueIds)
print generated data
in this solution i have:
insertUserJoinedMessageAndSendMessage(userPhoneNumbers, assignedUserId.id)
.then(function (t) {
return getOwnerPhoneNumberUniqueIds(userPhoneNumbers);
})
.then(function (result) {
log.info(result);
})
.catch(function (error) {
log.info(error);
});
methods, insertUserJoinedMessageAndSendMessage method work fine without any problem, i want to get generated data on nested Promise as getUserId() from getOwnerPhoneNumberUniqueIds() Promise function, but i can't print data on this part of code as log.info(result); because i can't return array from getOwnerPhoneNumberUniqueIds()
function insertUserJoinedMessageAndSendMessage(userPhoneNumbers, ownerUserId) {
return new Promise(function (resolve, reject) {
let query = "INSERT INTO `userJoinedMobileNumbers` (`id`, `userId`, `nameAndFamily`, `mobileNumber`, `created_at`, `updated_at`) VALUES ";
userPhoneNumbers.map(function (curr) {
query += "(NULL, " + ownerUserId + ", " + curr.contactName + ", " + curr.contactPhone + ", CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),";
});
query = query.substr(0, query.length - 1) + ";";
connection.query(query, function (err, results) {
if (err) return reject(err);
resolve(true);
});
});
}
function getOwnerPhoneNumberUniqueIds(data) {
return Promise.all(data.map(function (curr) {
return getUserId(curr.contactPhone)
.then(function (data) {
log.info("1) " + data);
return {id: data};
});
})).then(function (accountNumbers) {
log.info("2) " + accountNumbers);
return accountNumbers
}).catch(function (err) {
console.log(err);
});
}
function getUserId(contactPhone) {
return new Promise(function (resolve, reject) {
var query = "SELECT id FROM sendMessageUserJoined WHERE `phoneNumber` ='" + contactPhone + "'";
connection.query(query, function (err, results) {
if (err) return reject(err);
if (results.length > 0) {
log.info("0) " + results[0].id);
resolve(results[0].id);
}
});
});
}
in log.info("0) " + results[0].id); i get result of sql command and that return id successful to getOwnerPhoneNumberUniqueIds() and i can print result with this part of code as log.info("1) " + data);, now how can i return that on:
.then(function (accountNumbers) {
log.info("2) " + accountNumbers);
return accountNumbers
})
log.info("2) " + accountNumbers);
dont print result which returned by return {id: data};
The problem is in getUserId.
In some cases you wouldn't resolve or reject the promise. So your Promise.all returned promise maintained pending.
function getUserId(contactPhone) {
return new Promise(function (resolve, reject) {
var query = "SELECT id FROM sendMessageUserJoined WHERE `phoneNumber` ='" + contactPhone + "'";
connection.query(query, function (err, results) {
if (err) return reject(err);
if (results.length > 0) {
log.info("0) " + results[0].id);
resolve(results[0].id);
}
else { //this part is missing
resolve(); //or reject
}
});
});
}

Cant set headers after they are sent node.js

I am trying to combine multiple textfiles,convert them in a single zip file using zip archiver.
exports.downloadFilesInZip = function(req, res, next) {
var respObj = {};
var file_names = [];
var projectId = 111;
var file_ids = 11111;
console.log(projectId);
db.getConnection(function (err, connection) {
if (err) {
debug(err);
next(err);
}
else {
var updateQuery = "select data from file_data where file_id IN (?)";
console.log(updateQuery);
connection.query(updateQuery,[file_ids], function (err, results) {
console.log("inside" + updateQuery);
if (err) {
connection.release();
console.log("error" + JSON.stringify(err));
debug(err);
next(err);
}
else {
async.eachSeries(results,function(item,loopCallBack){
var text = "";
console.log("hllllllll");
console.log(item.data);
console.log(JSON.parse(item.data));
document_text = JSON.parse(item.data);
console.log("dssddssdsdsdsdsd"+document_text);
for(var j=0; j < document_text.length ;j++)
{
text += document_text[j]['text'];
}
//file_names.push(convertStringToTextFile(text));
convertStringToTextFile(text,function(err,file_name){
if(err){
console.log(err);
loopCallBack(err);
}
else {
file_names.push(file_name);
loopCallBack();
}
})
},function(err){
if(err){
console.log(err);
next(err);
}
else {
var updateQuery = "select name from project where id in (?)";
console.log(updateQuery);
connection.query(updateQuery,[projectId], function (err, results) {
console.log("inside" + updateQuery);
connection.release();
if (err) {
console.log("error" + JSON.stringify(err));
debug(err);
next(err);
}
else {
var fileName_link = JSON.stringify(results[0].name);
console.log("projectname"+fileName_link);
convertTextFilesToZip(file_names,fileName_link, function (err, filename) {
if (err) {
console.log(err);
next(err);
}
else {
console.log("filename link" + filename);
res.json({
status: 0,
file_link: filename
});
}
});
}
});
}
});
}
});
}
});
}
}
convertStringToTextFile = function(text,cb){
var json_filename = 'tmp/file_'+uuid.v4().replace('-','')+'.txt';
fs.writeFile(json_filename, text , function (err) {
if (err) {
debug(err);
cb(err);
}
else{
cb(null,json_filename);
}
});
};
convertTextFilesToZip = function(textFiles,file_link,cb){
console.log("textfiles"+textFiles);
var filename = 'reports/'+JSON.parse(file_link)+'_extractedText.zip';
var output = fs.createWriteStream(filename);
output.on('close', function() {
console.log(zipArchive.pointer() + ' total bytes');
console.log('archiver has been finalized and the output file descriptor has closed.');
});
zipArchive.on('error', function(err) {
cb(err);
});
zipArchive.pipe(output);
zipArchive.bulk([
{ expand: true, src: textFiles }
]);
zipArchive.finalize();
cb(null,filename);
}
It works okay the first time and after that it throws this error.I have checked other posts in which res is returned twice but i couldn't find it.It says that can't set headers after they are sent.I think the problem is in the convertTextFilesToZip function but i cant seem to pinpoint the exact location which is generating the error.ANy help is appreciated.
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:350:11)
at ServerResponse.header (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/express/lib/response.js:700:10)
at ServerResponse.send (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/express/lib/response.js:154:12)
at fn (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/express/lib/response.js:934:10)
at View.exports.renderFile [as engine] (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/jade/lib/index.js:374:12)
at View.render (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/express/lib/view.js:93:8)
at EventEmitter.app.render (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/express/lib/application.js:566:10)
at ServerResponse.res.render (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/express/lib/response.js:938:7)
at /Users/zeeshandar/Desktop/Agreements_info/agreements_info/app.js:207:13
at Layer.handle_error (/Users/zeeshandar/Desktop/Agreements_info/agreements_info/node_modules/express/li b/router/layer.js:58:5)
Making my comment into an answer since it appears to have led to the solution.
The variable zipArchive is not initialized in convertTextFilesToZip() therefore you are reusing that variable from one function call to the next and that seems unlikely to be the right implementation.
Also, I would expect your method calls to zipArchive to be asynchronous and it doesn't look like your are coding for that since the callback is called before you have any sort of completion notification.

Resources