I am trying to call a function inside my post API. I have multiple queries and want to wait for the function to complete in order to execute the next queries. I am having an issue here. The function isn't completing the execution and the rest of the API gets executed as expected. How can I wait for the function to complete its execution? I have searched but couldn't find something convenient and related to my code.
Here's the code:
Node.js
function verifyEmail(mailToUpper)
{
var emailResult;
db2.open(mydbConnection, (err, conn) => {
if(!err)
{
console.log("Connected Successfully");
}
else
{
console.log("Error occurred while connecting to the database " + err.message);
}
conn.query(checkEmailQuery, [mailToUpper], (err, results) => {
if(!err)
{
if(results.length > 0)
{
// res.write("Email already exists");
emailResult = 0;
}
else
{
emailResult = 1;
}
}
conn.close((err) => {
if(!err)
{
console.log("Connection closed with the database");
}
else
{
console.log("Error occurred while trying to close the connection with the database " +
err.message);
}
})
})
})
return emailResult;
}
router.post('/api/postData', (req, res) => {
//some stuff
var waitingForResult;
setTimeout(() => {
waitingForResult = verifyEmail(mailToUpper);
}, 2000)
console.log(waitingForResult); //throwing an error of undefined
if(waitingForResult === 1) //not executing this
{
//my other queries
}
else //always executes this
{
res.send("Email already exists");
}
});
function verifyEmail(mailToUpper) {
return new Promise((resolve, reject) => {
db2.open(mydbConnection, (err, conn) => {
if (!err) {
console.log("Connected Successfully");
} else {
console.log("Error occurred while connecting to the database " + err.message);
}
conn.query(checkEmailQuery, [mailToUpper], (err, results) => {
if (!err) {
if (results.length > 0) {
// res.write("Email already exists");
resolve(0);
} else {
resolve(1);
}
}
conn.close((err) => {
if (!err) {
console.log("Connection closed with the database");
} else {
console.log("Error occurred while trying to close the connection with the database " +
err.message);
}
})
})
})
})
}
router.post('/api/postData', async (req, res) => {
const waitingForResult = await verifyEmail( mailToUpper );
if( waitingForResult === 1 ){
//my other queries
} else {
res.send("Email already exists");
}
});
Related
I am using node-async-loop for asyncronous programming
var array = ['item0', 'item1', 'item2'];
asyncLoop(array, function (item, next)
{
do.some.action(item, function (err)
{
if (err)
{
next(err);
return;
}
next();
});
}, function (err)
{
if (err)
{
console.error('Error: ' + err.message);
return;
}
console.log('Finished!');
});
Like this I am using three async loops one under one.
I want to send the response only after the third inner loop ends. How can I do so?.
Here is the link for node-async-loop (https://www.npmjs.com/package/node-async-loop)
here is my code which i writing but whnever i want to response when the last loop completes it say can set header after send to cliend.
also in console log i am getting data every time when data coming from query.
const id = req.params.id;
finalData = [];
tb_user.findOne({ where: { id: id } }).then((userRiverSys, err) => {
if (userRiverSys) {
// console.log(userRiverSys.regionJson)
asyncLoop(userRiverSys.regionJson, function (item, next) {
// console.log("item", item);
tb_riverSystems.findAll(
{
where: { regionId: item.id }
}).then((findriverSys, err) => {
if (err) {
next(err);
return;
}
// console.log("findriverSys", findriverSys);
if (findriverSys) {
asyncLoop(findriverSys, function (item1, next1) {
if (err) {
next(err);
return;
}
// console.log("item1", item1.dataValues);
tb_facilities.findAll(
{
where: { riverSystemId: item1.dataValues.id }
}).then((findFacilities) => {
if (findFacilities) {
// console.log("findFacilities", findFacilities[0].dataValues.name);
asyncLoop(findFacilities, function (item2, next2) {
if (err) {
next(err);
return;
}
tb_userAccess.findAll(
{
where: { facilityId: item2.dataValues.id }
}).then((userAccessFacilities, err) => {
// console.log("userAccessFacilities", userAccessFacilities[0].dataValues);
// var i = 0;
asyncLoop(userAccessFacilities, function (item3, next3) {
finalData.push({
UserId: item3.userid,
facilityId: item3.facilityId,
})
next3();
},
function (err) {
if (err) {
console.error('Error: ' + err.message);
return;
}
// i++;
// console.log('Finished!!!!');
// if (userAccessFacilities.length === i) {
// console.log("finalData", i);
// // res.json({"status":"true", "message":"update OrgChallenge"})
// }
})
return res.json({"status":"true", "message":"update OrgChallenge"})
// console.log("finalData", finalData);
})
next2();
}, function (err) {
if (err) {
console.error('Error: ' + err.message);
return;
}
console.log('Finished!!!');
});
}
});
next1();
}, function (err) {
if (err) {
console.error('Error: ' + err.message);
return;
}
console.log('Finished!!');
});
}
});
next();
}, function (err) {
if (err) {
console.error('Error: ' + err.message);
return;
}
console.log('Finished!');
});
} else {
console.log("err3", err)
}
})
If you promisify your asynchronous action (so it returns a promise), then you can just use a regular for loop and async/await and there is no need for a 3rd party library to sequence your asynchronous loop. This is modern Javascript:
const { promisify } = require('util');
do.some.actionP = promisify(do.some.action);
async function someFunction() {
const array = ['item0', 'item1', 'item2'];
for (let item of array) {
let result = await do.some.actionP(item);
// do something with result here
}
return someFinalResult;
}
someFunction().then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});
FYI, in real code, many (or even most) asynchronous operations now offer promisified versions of their API already so usually you don't even need to do the promisify step any more. For example, pretty much all databases already offer a promise interface that you can just use directly.
const loop = async (arr, results = []) => {
const item = arr.shift()
if (!item) {
console.log("DONE");
return results;
}
// as async function
await new Promise(resolve => {
resolve(results.push(`asynced-${item}`))
})
return loop(arr, results);
}
(async () => {
const result = await loop(["item0", "item1", "item2"])
console.log(result);
})();
I'd be happy if I can help you.
but this script uses a recursive function instead of node-async-loop.
so this might not be suitable for you.
I'm new to working with Active Directory in general. I'm trying to update the thumbnailPhoto attribute using ldapjs npm package I have my code setup to be able to update attributes in general and it works well.
I get my user like so:
const customeParser = function(entry, raw, callback){ if (raw.hasOwnProperty("thumbnailPhoto")){ entry.thumbnailPhoto = raw.thumbnailPhoto; } callback(entry) }
find(filter, cb) {
const client = ldap.createClient(this.ldapOptions)
client.on('error', err => {
console.error(err.message)
})
//Serach for users
client.bind(
this.options.dn,
this.options.password,
(err) => {
if (err) {
console.error((new Date).toUTCString(), 'Initial Bind Error', err)
client.unbind(() => {
client.destroy()
cb(err)
})
} else {
client.search(
'DC=foo,DC=local', {
scope: 'sub',
attributes: [
'distinguishedName',
'name',
'sn',
'givenName',
'mail',
'sAMAccountName',
'telephoneNumber',
'thumbnailPhoto',
// 'photoURL',
// 'profileImage',
'extensionAttribute1',
'msExchExtensionCustomAttribute1'
],
entryParser: customeParser,
filter: `${filter}`
},
(err, ee) => {
if (err) {
console.log((new Date).toUTCString(), 'SEARCH RESULT', err)
client.unbind(() => {
client.destroy()
cb(err)
})
}
ee.on('searchEntry', (entry) => {
ee.on('end', () => {
client.unbind(() => {
client.destroy()
cb(null, entry.object)
})
})
});
});
}
});
}
I call my modifyUser method from my LDAP class like so:
let changes = {
thumbnailPhoto: 'http://<ip>:<port>/img/photo.jpg'
}
ad.modifyUser(user.dn, changes, function (err, mod) {
if (err) {
console.log('ERROR: ' + JSON.stringify(err));
return;
}
if (!mod) {
console.log('Search: ' + mod + ' not found.');
} else {
console.log('MOD: ', JSON.stringify(mod));
}
})
modifyUser:
modifyUser(user, attributes, cb) {
const client = ldap.createClient(this.ldapOptions)
client.on('error', err => {
console.error(err.message)
})
//Serach for users
client.bind(
this.options.dn,
this.options.password,
(err) => {
if (err) {
console.error((new Date).toUTCString(), 'Initial Bind Error', err)
client.unbind(() => {
client.destroy()
cb(err)
})
} else {
var change = new ldap.Change({
operation: 'replace',
modification: attributes
});
console.log('CHANGE: ', attributes)
client.modify(user, change, function(err) {
if(err) console.error('ERROR: ', err);
},
(err, ee) => {
if (err) {
console.log((new Date).toUTCString(), 'SEARCH RESULT', err)
client.unbind(() => {
client.destroy()
cb(err)
})
}
ee.on('searchEntry', (entry) => {
ee.on('end', () => {
client.unbind(() => {
client.destroy()
cb(null, entry.object)
})
})
});
});
}
});
}
When I update the photo using my LDAP Tool it converts it to what i believe to be an octet or some sort of hex value. How do i mimic that in nodejs?
Am I on the right track? All other attributes get updated instantly using the code above, but the image fails to update...
Also is there a way to update multiple attributes at once? I get the error that only one attribute can be modified at a time.
Thanks in advance for your time!
I am trying to call method get_radar_life_cycle from app.get("/api/radar_cloning and it throws the error shown below,
error is coming from line return done(null,documents) how do I return documents back to my API call?
METHODS:-
let get_cloned_radars = function(documents, done) {
let complete_radar_list=[]
for (let i = 0; i < documents.length; i++) {
complete_radar_list.push(documents[i]['orgRadar']);
for (let j = 0; j < documents[i]['clonedRadarsdetailslist'].length; j++) {
complete_radar_list.push(documents[i]['clonedRadarsdetailslist'][j]['clonedRadar']);
}
}
data = complete_radar_list
return done(null, data)
}
let get_radar_life_cycle = function(data,done) {
console.log("data after get_radar_life_cycle")
console.log(data)
Radar_life_cycle.find({orgRadar: {$in:data}})
.then(documents => {
console.log(documents) --> shows correct data
});
return done(null,documents) --> Error is coming from this line
};
API call:
app.get("/api/radar_cloning", (req, res, next) => {
Radar_cloning.find({orgRadar: {$in:req.query.params.split(',')}})
.then(documents => {
get_cloned_radars(documents, function(err,data) {
if (err) {
res.json(err);
if (data!=null){
console.log(data)
}//end for data
}//end of (Err)
});//get_cloned_radars
get_radar_life_cycle(data, function(err,radar_life_cycle_data) {
if (err) {
res.json(err);
console.log(radar_life_cycle_data)
}//end for radar_life_cycle_data
}//end of (Err)
});//end of get_radar_life_cycle
});
});
ERROR:-
(node:10065) UnhandledPromiseRejectionWarning: ReferenceError: documents is not defined
You are trying to access documents outside of its scope, the scope being everything between the { and }. So you cannot access it below the .then(() => {}) scope.
Luckily you are are providing a callback function called done(err, radar_life_cycle_data), which you can use anywhere in the scope of the get_radar_life_cycle(documents, done) function. Even the scopes inside of its scope. When you are calling the done function, what you are basically doing is calling this function (well it has some syntax errors, so I cleaned it up)
function(err,radar_life_cycle_data) {
if (err) {
res.json(err);
console.log(radar_life_cycle_data)
}
}//end for radar_life_cycle_data
which then gets executed
So the solution:
Move your done in your .then(() => {}) scope like this:
let get_radar_life_cycle = function(data,done) {
console.log("data after get_radar_life_cycle")
console.log(data)
Radar_life_cycle.find({orgRadar: {$in:data}})
.then(documents => {
console.log(documents) // --> shows correct data
done(null,documents) // --> No error coming from this line
});
};
Same goes for the data it is not in the scope of the get_cloned_radars
app.get("/api/radar_cloning", (req, res, next) => {
Radar_cloning.find({orgRadar: {$in:req.query.params.split(',')}})
.then(documents => {
get_cloned_radars(documents, function(err,data) {
if (err) {
res.json(err);
if (data!=null) {
console.log(data)
get_radar_life_cycle(data, function(err,radar_life_cycle_data) {
if (err) {
res.json(err);
console.log(radar_life_cycle_data)
} //end of (Err)
}); //end of get_radar_life_cycle
} //end for data
} //end of (Err)
}); //get_cloned_radars
});
But since your code is unreadable, here is a cleaned up version:
app.get("/api/radar_cloning", (req, res, next) => {
const radar_life_cycle_cb = function (err, data) {
if (err) {
res.json(err);
return;
}
console.log(data);
}
const cloned_radar_cb = function (err, data) {
if (err) {
res.json(err);
return;
}
if (data != null) {
get_radar_life_cycle(data, radar_life_cycle_cb);
}
};
Radar_cloning.find({orgRadar: {$in:req.query.params.split(',')}})
.then(documents => get_cloned_radars(documents, cloned_radar_cb));
}
Here is my code that tries to update a record in the db.
But if the record is not there then I want to insert it.
Is it OK to call client.query again? Or what's the best way to do it?
const {Pool} = require('pg');
const pool = new Pool(POSTGRES_CONFIG);
pool.connect((err, client, release) => {
if (err) {
return console.error('Error acquiring client', err.stack)
}
………
client.query(query, queryValues, (err, result) => {
release();
if(result.rowCount<=0){
//**** CAN I CALL IT AGAIN WITH OTHER PARAMETERS TO INSERT? ****
client.query(....... => {
release();
if (err) {
if(err.code === POSTGRES_ERRORS.UNIQUE_VIOLATION){
return console.error('KEY ALREADY EXISTS');
} else {
return console.error('query error', err);
}
}
}
}
});
});
It is perfectly OK as long as you call release after you're done with the client. From the docs:
You must call the releaseCallback or client.release (which points to
the releaseCallback) when you are finished with a client.
So, you could do this:
client.query(query, queryValues, (err, result) => {
// don't release just yet
if(result.rowCount<=0){
//**** CAN I CALL IT AGAIN WITH OTHER PARAMETERS TO INSERT? ****
client.query(....... => {
release(); // now you're done with the client so you can release it
if (err) {
if(err.code === POSTGRES_ERRORS.UNIQUE_VIOLATION){
return console.error('KEY ALREADY EXISTS');
} else {
return console.error('query error', err);
}
}
}
}
});
I have mocha tests. I will simplify as possible as I can.
I wonder how should I handle the errors in mocha tests. For example, if there is an error in getName, what should I do? How can I throw an error? Or should I use done(error) as;
it('trial', function(done) {
getName(function (name, err) {
if(err){
done(err); //what should I do here?
}else{
console.log(name);
}
});
});
If doneis called with a argument other than undefined, the test will fail and be reported as such. Other test will still be executed.
It allow you to test for success, but also for error:
it('succeed', (done) => {
myFunc('success', (err, res) => {
if(err) {
done(err);
} else if(res !== 'expected') {
done('Wrong result ' + res);
} else {
done();
}
});
});
it('fail with error 404', (done) => {
myFunc('fail', (err, res) => {
if(err) {
if(err === 404) {
done();
} else {
done('Error was expected to be 404, got ' + err);
}
} else {
done('Was expected to fail, got result ' + res + ' and no error');
}
});
});
it('succeed', (done) => {
try {
var res = myFuncSync('succeed');
} catch(err) {
done(err);
}
done();
});
it('fail with error 404', (done) => {
try {
var res = myFuncSync('succeed');
} catch(err) {
if(err === 404) {
done();
} else {
done('Error was expected to be 404, got ' + err);
}
}
done('Was expected to fail, got result ' + res + ' and no error');
});