I have return the function in mysql.js as :
function myFunction(resourceIdentifiers,callback){
dbconnection.execute( function(err,response) {
response.query('call SP_ExposePricingDetailforUI('
+ resourceIdentifiers + ')'
,function (err, rows, fields) {
console.log(rows);
});
}
);
return rows;
}
And tried to call it at another script file restservice.js as :
mysql.myFunction(resourceIdentifiers , function(err,rows) {
console.log(rows);
}
But I get error as the function myFunction is Undefined.
If mysql.myFunction is undefined, then you're probably not actually exporting it:
function myFunction(resourceIdentifiers, callback){
// ...
}
exports.myFunction = myFunction;
Function and variable declarations are "private" to the module by default. Only those members you explicitly export will be accessible from other modules.
You also won't be able to use return rows; as you're trying to. Asynchronous code is event driven and doesn't wait, which return would need it to do.
myFunction already has a callback argument and you're passing a function for the value. You just need to call it:
// ...
function (err, rows, fields) {
callback(err, rows);
}
// ...
You should also at least escape resourceIdentifiers when concatenating.
But, generally better is to use a placeholder (?) and the optional, 2nd argument to .query():
response.query(
'call SP_ExposePricingDetailforUI(?)',
[ resourceIdentifiers ],
function (err, rows, fields) {
callback(err, rows);
}
);
You just need to callback within the result of response.query. Something like this.
mysql.js:
function myFunction(resourceIdentifiers,callback){
dbconnection.execute( function(err,response) {
response.query('call SP_ExposePricingDetailforUI('
+ resourceIdentifiers + ')'
,function (err, rows, fields) {
callback(err, { rows: rows, fields: fields});
});
}
);
}
module.exports.myFunction = myFunction;
restservice.js:
mysql.myFunction(resourceIdentifiers , function(err,resp) {
console.log(resp.rows);
}
Update - removed the return rows statement that I missed the first time around.
Related
So I am doing a nodejs tutorial and it asks me to use modules to filter all the files in a directory. And I'm supposed to use the idiomatic approach to handle errors. Below is my modules.js and my main program.js, however, the program said that
Your additional module file [module.js] does not appear to pass back an
error received from fs.readdir(). Use the following idiomatic Node.js
pattern inside your callback to fs.readdir():
if (err) return
callback(err)
but I did handle the error on the first line using if (err)return callback(err);
Can someone please point out what I am doing wrong or what best practice I'm not following? Thanks
module.exports = function filterList(dirName, extName, callback) {
fs.readdir(dirName, function callback(err, list) {
if (err)
return callback(err);
for (var i = 0; i < list.length; i++) {
if (path.extname(list[i]) == '.' + extName) {
callback(null, list[i]);
}
};
});
}
my program.js is as follows
var myMod = require('./module');
function printOut(err, result) {
if (err) {
console.log(err);
};
console.log(result);
}
myMod(process.argv[2], process.argv[3], printOut);
You have two functions named callback here which is causing unexpected behavior.
Your main exported function takes an argument name callback. Then inside that you define another function named `callback':
function filterList(dirName, extName, callback){ // <-- callback as arg
fs.readdir(dirName, function callback(err, list) { // <-- callback defined again
if (err)
return callback(err); // <-- which function is this calling?
/* etc. */
}
When you finally return callback(err) you are calling the wrong function. You want to call the first one -- the one passed into filterList(), but the second one is in scope.
You could instead pass an anonymous function to fs.readdir since you never need to call it:
fs.readdir(dirName, function(err, list) {
if (err)
return callback(err); // <-- now there's only one call back
Now it's clear that you are calling the correct callback and it's more idiomatic.
You're shadowing your callback by naming the function the same as the argument. Try this:
module.exports = function filterList(dirName, extName, callback) {
fs.readdir(dirName, function cb(err, list) {
if (err) return callback(err);
for (var i = 0; i < list.length; i++) {
if (path.extname(list[i]) == '.' + extName) {
callback(null, list[i]);
}
};
});
}
Notice the rename of the second paramerter to fs.readdir is now named cb, you don't actually need to name it, but it does help for stack traces and logging.
One other thing, you are going to have an issue calling callback inside a loop. There are ways to break out of it and also ways to avoid having it in the loop.
I have functions in different place.(this is common function it will use many place.
So I tried to call the function using async parallel but its not working.
I attached the my code following:L
var userId = 33;
async.parallel({
video(userId, callback) {
callback(null, callback);
},
video1(userId, callback) {
callback(null, callback);
}
}, function(err, results) {
console.log(results);
});
function video (userId, callback) {
client.query("select youtube_id,title,id,thumbnail,search_item from resource order by random() limit 1 ", function(err, video) {
callback(err, video);
});
}
function video1(userId, callback) {
client.query("select youtube_id,title,id,thumbnail,search_item from resource1 order by random() limit 1 ", function(err, video1) {
callback(err, video1);
});
}
The {fnName()} syntax is a function declaration. You want to use a function call ... in fact you can just use async.parallel({video, video1}, (err, results) => console.log(results) to achieve the same effect... except that you also need to pass in userId. So what you actually intend is to call the function rather than declare it:
async.parallel([
callback => video(userId, callback),
]);
You need to pass function references to async.parallel() and you need to pass an array, not an object. You want the code to have this form:
async.parallel([fn1, fn2], finalCallback);
See the async.parallel() doc here for specific examples of the syntax you want to use.
Where fn1, fn2 and finalCallback are all function references that can be called by the async.parallel() infrastructure, not something you call yourself.
Change your code to this:
async.parallel([
function(callback) {
client.query("select youtube_id,title,id,thumbnail,search_item from resource order by random() limit 1 ", function(err, video) {
callback(err, video);
}),
},
function(callback) {
client.query("select youtube_id,title,id,thumbnail,search_item from resource order by random() limit 1 ", function(err, video1) {
callback(err, video1);
});
}
], function(err, results) {
console.log(results);
});
Presumably, your two database queries should be different somehow (your code showed them identical).
If your functions are already defined somewhere, then you can pass an anonymous function reference that will call them. You need to do this if your functions don't have the exact same calling convention that async.parallel() requires. You can do that like this:
async.parallel([function(callback) {
video(userId, callback);
}, function(callback) {
video1(userId, callback);
}], function(err, results) {
console.log(results);
});
I'm trying to export one function this way:
exports.query = function(request){
conn.query(request, function(err, rows, fields){
if(err) console.log(err);
return rows[0].id;
});
}
and using it:
var mysql = require('./mysql');
console.log(mysql.query('SELECT * FROM tablename'));
Proceeding this way for getting a result involves undefined as output.
How do I to fix this, please?
Note that when I just type console.log(rows[0].id) instead of return rows[0].id it sends back 123.
Thanks in advance!
In your example, the output is being returned to the anonymous function of the database query instead of the caller of the module. You can use a callback to return output to the caller of the module.
exports.query = function(request, callback){
conn.query(request, function(err, rows, fields){
if (err) {
callback(err);
} else {
callback(null, rows[0].id);
}
});
}
Then call it like
var mysql = require('./mysql');
mysql.query('SELECT * FROM tablename', function(err, results){
if (err) {
console.error(err);
} else {
console.log(results);
}
});
That's a problem of synchrony.
the conn.query function returns undefined because it finish its execution before the results are fetched (like almost any i/o related operation on js/node).
One possible solution to that, is to provide a callback to your query function.
exports.query = function(request, cb){
conn.query(request, function(err, rows, fields){
// some "special" processing
cb(err, rows, fields);
});
};
If you're not familiar with async functions, take a look on some articles about that:
http://justinklemm.com/node-js-async-tutorial/
https://www.promisejs.org/
thanks for your help...struggling big time with how to handle this properly. I'm in async now, having given up on my ability to write the callbacks properly. I have snippet where I'm passing a set of random numbers (eachrecord) and passing them through to a mongoose call. Trying to create a data set from the multiple queries I pass.
My issue is that no matter what I've done for 4 hours, the "newarray" variable is always empty.
Thank you for your help -
async.forEach(arLimit, function(eachrecord, callback){
newarray = new Array;
var query = UGC_DB_Model.find({}).skip(eachrecord).limit(-1);
query.execFind(function (err, data) {
if (err)
console.log(err);
else {
newarray.push(data);
}
});
callback(null, newarray);
}, function(err, result) {
if (err) return next(err);
console.log("(it's empty): " + result);
});
There are several issues with your code:
async.forEach isn't meant to 'generate' results, that's what async.map is for;
you need to call the callback only when execFind is done, and not immediately after calling it;
your newarray is probably not necessary;
So try this instead:
async.map(arLimit, function(eachrecord, callback){
var query = UGC_DB_Model.find({}).skip(eachrecord).limit(-1);
query.execFind(function (err, data) {
if (err)
callback(err); // pass error along
else {
callback(null, [ data ]);
// although I think you mean this (because 'data' is probably an array already)
// callback(null, data);
}
});
}, function(err, result) {
if (err) return next(err);
console.log("(it's empty): " + result);
});
I have a parent function which has multiple callbacks and need to pass the result of the innermost callback to the function which calls this "parent" function. As NodeJS is asynchronous, my parent function obviously always returns before the callbacks are executed.
How can I make my callbacks return to the caller?
Code example that I am using right now -
var addNewUser = function(hash,name,number,time,syncTime){
// check here if the user exists or not by querying the phone number first
connection.query('SELECT user_id FROM users WHERE user_phone_number ="' +number+'"',function(err,rows,fields){
if(rows[0]) return false;
connection.query('INSERT INTO users (authorization_hash,user_name,user_phone_number,user_local_time,is_active,last_synced) VALUES ("'+hash+'","'+name+'","' + number+'","' +time+'","1","'+syncTime+'")',function(err,rows,fields){
if(err) throw err;
return true;
});
});
}
I Want to be able to return this callback return to the caller function.
Have addNewUser accept a callback as its last argument and have the innermost function call the callback with the value.
Alternatively, you could look into having addNewUser return a promise. RSVP or Q are implementations of the Promises/A :
function addNewUser(hash,name,number,time,syncTime) {
var deferred = Q.defer();
connection.query("SELECT ...", function(err, rows, fields) {
if(err) { deferred.reject(err); }
if(rows[0]) { deferred.reject("some reason"); }
connection.query("INSERT INTO ...", function(err, rows, fields) {
if(err) { deferred.reject(err); }
deferred.resolve(rows[0]); // Whatever addNewUser would return normally
});
});
return deferred.promise;
}
Then the caller would use it like this:
addNewUser(...).then(function(newUserAdded) {
// Do something with newUserAdded here
}, function(err) {
// Do something with the error here
});