call synchrounously process in node.js - javascript

I am stuck in nodejs during calling of zendesk api.
As i called zendesk.tickets.incremental Api, it provides me ticketId and that used in another function for getting any change from previous by calling zendesk.tickets.exportAudit.
I also get response too but during fetching the data another ticketId called so previously flag an error in response "error: item not found " and than fetch the data for new ticketId and so on.
What I need, I need it block the process until data of first Id completely .
This is my code.
//Calling ticketIncremental Details ticketId (likes 1, 2 etc)
app.get('/', function (req, res) {
zendesk.tickets.incremental(0, function(err, statusList, body, responseList, resultList) {
if (err) {
console.log(err);
return;
}
var ticketIncreDetails = (JSON.stringify(body));
res.end(ticketIncreDetails);
for (var i=0; i< body.length; i++ ) {
ticketValues(body[i].id) //within this function another API of zendek calling for exportAudit
}
});
//This is for exportAudit
function ticketValues(ticketId) {
zendesk.tickets.exportAudit(ticketId, function(err,statusList, body, responseList, resultList) {
if(err) {
console.log(err);
return;
}
console.log("ticketExportAudit: " + JSON.stringify(body)) });

As #qxz say, it's better to check out if there is sync package or not, or you need to handle this focusing on callback because zendesk.tickets.exportAudit need time to complete its work, but for loop wouldn't act like that, the code below handle this problem with callback, you could have a look.
//Calling ticketIncremental Details ticketId (likes 1, 2 etc)
app.get('/', function (req, res) {
zendesk.tickets.incremental(0, function(err, statusList, body, responseList, resultList) {
if (err) {
console.log(err);
return;
}
var ticketIncreDetails = (JSON.stringify(body));
res.end(ticketIncreDetails);
ticketValues(body,body.length,0);
//ticketValues(body,body.length,0,function(){..if you wanna do something after..});
});
});
//This is for exportAudit
function ticketValues(ticket,length,index,callback) {
zendesk.tickets.exportAudit(ticke[index].id, function(err,statusList, body, responseList, resultList) {
if(index<length){
if(err) {
console.log(err);
return;
}else{
console.log("ticketExportAudit: " + JSON.stringify(body));
index++;
ticketValues(ticket,length,index,callback);
}
}else{
if(callback)
callback();
}
});
}

Related

Javascript async completed callback executing before async functions complete

I've been trying to diagnose this bug for some time now but can't figure out why my completed() function executes before all my asynch functions are done. I'm using the async library:
async.forEach(data.DBInstances, function (dbInstance, fcallback) {
let dbtype = dbInstance.Engine;
let logFilename = log[dbtype].log();
let instanceId = dbInstance.DBInstanceIdentifier;
if (tagFilter) {
let arn = dbInstance.DBInstanceArn;
checkRDSTag(arn, tagFilter, function (err, found) {
if (!err) {
//tag was found, continue processing and check other filters...
if (found) {
if (noFilter || (instanceTypes && instanceTypes.indexOf(dbtype))) {
//console.log('db type is: ' + dbtype);
processOrCreateLog(instanceId, dbType, function (err, data) {
if (!err) {
console.log("Data: " + JSON.stringify(data));
completed.push(data);
fcallback(null);
} else {
cb(err, null);
}
});
}
} else {
//tag wasn't found but was specified, don't process anything...
console.log("tag specified was not found on instance: " + instanceId);
}
} else {
console.log("Error checking RDS Tag");
cb(err, null);
}
});
}
//only process filtered types...
else if (noFilter || (instanceTypes && instanceTypes.indexOf(dbtype))) {
console.log('db type is: ' + dbtype);
processOrCreateLog(instanceId, dbtype, fcallback, function (err, data, fcallback) {
if (!err) {
console.log("Data: " + JSON.stringify(data));
completed.push(data);
fcallback(null);
} else {
cb(err, null);
}
});
}
}, testme(completed));
My async functions are running correctly and each completing correctly but my testme(completed) runs immediately before any of my asynch functions ever finish. Not sure why..
my testme(completed) is simply:
function testme(completed) {
console.log("Completed: " + JSON.stringify(completed));
}
One note, my function to execution on each element itself has asynch functions inside of it (checkRDSTag(), processOrCreateLog(), etc). I'm guessing its something to do with the callback() that async is expecting / tracking executing out of place or something? Not really sure..
Retrun callback only when last item iterating
var index=0;
async.forEach(data.DBInstances, function (dbInstance, fcallback) {
let dbtype = dbInstance.Engine;
let logFilename = log[dbtype].log();
let instanceId = dbInstance.DBInstanceIdentifier;
if (tagFilter) {
let arn = dbInstance.DBInstanceArn;
checkRDSTag(arn, tagFilter, function (err, found) {
if (!err) {
//increament index here
index++;
//tag was found, continue processing and check other filters...
if (found) {
if (noFilter || (instanceTypes && instanceTypes.indexOf(dbtype))) {
//console.log('db type is: ' + dbtype);
processOrCreateLog(instanceId, dbType, function (err, data) {
if (!err) {
console.log("Data: " + JSON.stringify(data));
completed.push(data);
//check if last item running
if(index===data.DBInstances.length){
return fcallback(null);
}else{
fcallback()
}
} else {
cb(err, null);
}
});
}
} else {
//tag wasn't found but was specified, don't process anything...
console.log("tag specified was not found on instance: " + instanceId);
}
} else {
console.log("Error checking RDS Tag");
cb(err, null);
}
});
}
//only process filtered types...
else if (noFilter || (instanceTypes && instanceTypes.indexOf(dbtype))) {
console.log('db type is: ' + dbtype);
processOrCreateLog(instanceId, dbtype, fcallback, function (err, data, fcallback) {
if (!err) {
console.log("Data: " + JSON.stringify(data));
completed.push(data);
//check if last item running
if(index===data.DBInstances.length){
return fcallback(null);
}else{
fcallback()
}
} else {
cb(err, null);
}
});
}
}, testme(completed));
My problem ended up being in my other asynchronous call (processOrCreateLog()) within my iteratee. There was flow control logic in my asynchronous calls that didn't callback so fcallback() never ran.
Also to clarify, async is the async node.js library: https://caolan.github.io/async/docs.html#each
As long as you execute the callback on the iteratee for each element with either an error or null it can track all executions and will then run your final callback properly.

How to check for document already in database before POST - MongoDB, NodeJS

I am trying to check to see if a document is already in the database before posting. I am posting via a jQuery.post() method to my endpoint which is api/songs.
What I want to check is to see if the song is already in the database. I can check that by querying the songId parameter that I am pushing to the database. If the song is already in the database I want to increment a number by 1.
What I have been trying to do is use mongo's findOne(), but I can't get it to work in the POST. My post route looks like this:
router.post('/api/songs', function(req, res){
if(Song.findOne({songId: req.body.songId}).length > -1){
console.log('already in there fam')
} else{
var song = new Song();
song.artistName = req.body.artistName;
song.titleName = req.body.titleName;
song.songId = req.body.songId;
song.songImg = req.body.songImg;
song.save(function(err) {
if (err) {
console.log("Error: " + err)
} else {
console.log("created fam")
}
})
};
console.log(song);
return res.json({message: "SongCreated"})
})
My problem is that I can't figure out what the findOne is returning. I want it to return a boolean so i've tried count() and length() but can't get it to return true. The req posts to the DB no matter what.
Any ideas?
All i/o operations in node.js are asynchronous. Your Song.findOne operation is asynchronous as well. You should wait for it to complete via callback functionality and then check the result of it.
Mongoose findOne method returns a promise. You can read more info about it here.
Example of promise execution:
var query = Song.findOne({songId: req.body.songId})
query.exec(function(err, song) {
})
Try the following code:
router.post('/api/songs', function(req, res){
Song.findOne({songId: req.body.songId}, function(err, song){
if (err) {
return console.log("Error: " + err)
}
if(song){
return console.log('already in there fam')
}
var song = new Song();
song.artistName = req.body.artistName;
song.titleName = req.body.titleName;
song.songId = req.body.songId;
song.songImg = req.body.songImg;
song.save(function(err) {
if (err) {
console.log("Error: " + err)
} else {
console.log("created fam")
}
})
console.log(song);
return res.json({message: "SongCreated"})
})
})

How to make my code clearer

The code is for handling the POST request within Expressjs and mongodb
router.post('/', function(req, res){
var data = req.body;
Tag.find({name: data.name}).limit(1).exec( function(err, result){
if(err){
} else {
if(result.length > 0){ // Already exist a tag with same name
res.status(400).end('Already exist!');
} else { // Save the new Tag to database
var tag = new Tag();
tag.name = data.name;
tag.lastModifier = req.user?req.user.username:"system";
tag.lastModified = Date.now();
tag.save(function(err){
if(err){
res.status(400).json({
message: "insert tag error"
});
} else {
Tag.findOne(tag, function(err, result){
if(err){
res.status(400).json({
message: "some error.."
});
} else {
//res.status(400).end('same tag name');
res.status(201).json({
_id: result._id
});
}
});
}
});
}
}
});
});
The stairs in the last 9 lines are terrible....please teach me how could I make this mess clearer?
You can use named functions instead of some of the function expressions:
router.post('/', function(req, res){
var data = req.body;
Tag.find({name: data.name}).limit(1).exec( function(err, result){
if(err){
} else {
if(result.length > 0){ // Already exist a tag with same name
res.status(400).end('Already exist!');
} else { // Save the new Tag to database
var tag = new Tag();
tag.name = data.name;
tag.lastModifier = req.user?req.user.username:"system";
tag.lastModified = Date.now();
tag.save(save(err));
}
}
});
});
function save(err){
if(err){
res.status(400).json({
message: "insert tag error"
});
} else {
Tag.findOne(tag, handleResult(err, result));
}
}
function handleResult(err, result){
if(err){
res.status(400).json({
message: "some error.."
});
} else {
//res.status(400).end('same tag name');
res.status(201).json({
_id: result._id
});
}
}
(You can surely name them a little more appropriate for the situation, but it shows the principle.)
router.post('/', function(req, res){
var data = req.body;
Tag.find({name: data.name}).limit(1).exec(cbExec);
});
function cbExec(err, result){
if(err){
} else {
if(result.length > 0){ // Already exist a tag with same name
res.status(400).end('Already exist!');
} else { // Save the new Tag to database
var tag = new Tag();
tag.name = data.name;
tag.lastModifier = req.user?req.user.username:"system";
tag.lastModified = Date.now();
tag.save(cbSave);
}
}
}
function cbSave(err){
if(err){
res.status(400).json({message: "insert tag error"});
} else {
Tag.findOne(tag, cbTag);
}
}
function cbTag(err, result){
if(err){
res.status(400).json({message: "some error.."});
} else {
//res.status(400).end('same tag name');
res.status(201).json({_id: result._id});
}
}
I really recommend you to try promises. There are many implementations available for JavaScript and Node.js.
A promise basically encapsulates an asynchronous operation into a value, which allows you to get rid of these horrible nested callbacks. They also allow you to chain asynchronous operations more easily.
What you're forced to do in your callback-based code is to check errors at every level, which can get rather tedious if your error handling could be at one place. Promises will propagate the error, allowing easy handling in one place.
Here are some references:
http://www.html5rocks.com/en/tutorials/es6/promises/
https://developer.mozilla.org/cs/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://www.promisejs.org/
It might take a little while to adjust to using them, but trust me, it is absolutely worth it.
You can separate the cod a little bi more. Instead of creating lambda functions create normal ones. You can get rid of one pair of braces in 4th line
if(err){
} else {
using if(!err)

Node.js find method works weird

I have this Node.js method for GET queries
app.get('/:tableName', function(req, res) {
var schema = require('./schema/' + req.param('tableName'));
var q = unescape(Object.keys(req.query)[0]);
console.log('query:' + q);
schema.find(q, function(err, result) {
if (err) {
console.log(err);
res.status(500).json({status: 'failure'});
}
if (result) {
res.json(result);
} else {
res.json({status: 'not found'});
}
});
});
The strage, that if I call it i.e. whit this input .. (it is exactly the value of var q)
{
"remoteID" : "80E75ED5-B696-446E-9AA7-9B170350D7E6"
}
.. I get back 3 items but non of them match the condition, basically it returns all the items in table.
[{"lastName":"K","remoteID":"D5DC51C1-C415-4073-A647-1D41BB47D03E","password":"p","firstName":"J","email":"xxx","airline":"73C02335-C019-419E-BCC7-C87537F38492","userName":"J","_id":"5353b639889a61000038848c","__v":0},
{"lastName":"asd","remoteID":"C471495C-C218-4440-BA81-7BD37CBB5605","password":"wn831","firstName":"asd","email":"asd#asd.hu","airline":"73C02335-C019-419E-BCC7-C87537F38492","userName":"ASA","_id":"5353b639889a610000388491","__v":0},
{"remoteID":"5A0D51DE-DCD0-4E3E-9D97-7CAD066DB68A","userName":"R","password":"R","_id":"5353b639889a610000388492","__v":0}]
One important line was missing:
var jq = JSON.parse(q);
schema.find(jq, function(err, result) {
find() method requires not string but JSON object.

Node/Express - How to wait until For Loop is over to respond with JSON

I have a function in my express app that makes multiple queries within a For Loop and I need to design a callback that responds with JSON when the loop is finished. But, I'm not sure how to do this in Node yet. Here is what I have so far, but it's not yet working...
exports.contacts_create = function(req, res) {
var contacts = req.body;
(function(res, contacts) {
for (var property in contacts) { // for each contact, save to db
if( !isNaN(property) ) {
contact = contacts[property];
var newContact = new Contact(contact);
newContact.user = req.user.id
newContact.save(function(err) {
if (err) { console.log(err) };
}); // .save
}; // if !isNAN
}; // for
self.response();
})(); // function
}; // contacts_create
exports.response = function(req, res, success) {
res.json('finished');
};
There are a few problems with your code besides just the callback structure.
var contacts = req.body;
(function(res, contacts) {
...
})(); // function
^ you are redefining contacts and res in the parameter list, but not passing in any arguments, so inside your function res and contacts will be undefined.
Also, not sure where your self variable is coming from, but maybe you defined that elsewhere.
As to the callback structure, you're looking for something like this (assuming contacts is an Array):
exports.contacts_create = function(req, res) {
var contacts = req.body;
var iterator = function (i) {
if (i >= contacts.length) {
res.json('finished'); // or call self.response() or whatever
return;
}
contact = contacts[i];
var newContact = new Contact(contact);
newContact.user = req.user.id
newContact.save(function(err) {
if (err)
console.log(err); //if this is really a failure, you should call response here and return
iterator(i + 1); //re-call this function with the next index
});
};
iterator(0); //start the async "for" loop
};
However, you may want to consider performing your database saves in parallel. Something like this:
var savesPending = contacts.length;
var saveCallback = function (i, err) {
if (err)
console.log('Saving contact ' + i + ' failed.');
if (--savesPending === 0)
res.json('finished');
};
for (var i in contacts) {
...
newContact.save(saveCallback.bind(null, i));
}
This way you don't have to wait for each save to complete before starting the next round-trip to the database.
If you're unfamiliar with why I used saveCallback.bind(null, i), it's basically so the callback can know which contact failed in the event of an error. See Function.prototype.bind if you need a reference.

Categories