NodeJS wait until mySQL query is completed - javascript

I trying to pass a object from the controller to the view. Because I want to my model separate my query's from the controller I'm loading a JS object (model).
My model looks as follows:
function MyDatabase(req) {
this._request = req;
this._connection = null;
this.init();
};
MyDatabase.prototype = {
init: function() {
this._request.getConnection( function(err, con) {
if(err) return false;
return this._connection = con;
}.bind(this));
},
getFromTable: function(table) {
this._connection.query('SELECT * FROM '+ table +';', function(err, result) {
if(err)
return false;
else if( !result )
return {error: 'Error bij het ophalen van foto\'s'};
else
return result;
}.bind(this));
}
};
module.exports = MyDatabase;
But I can't figure out how to wait until this query is completed in my controller. I've found the async module and tried multiple function like waterfall and parallel, but none of them worked for me (or I didn't use it as supposed to).
My controller currently looks as seen below:
var myDatabase = require('../dbmodel');
router.get('/', function(req, res, next) {
var db = new myDatabase(req);
async.waterfall([
function(callback) {
var db = new myDatabase(req);
var photos = db.getFromTable('photos');
callback(null, photos);
}
], function(p) {
res.locals.photos = p;
res.render('photos');
} );
});
What am I doing wrong? I do understand that NodeJS works async and doesn't wait for any function to be completed. But there must be a way this is possible. What am I doing wrong, or what do I misunderstand?
Thanks in advanced! ;)

The getFromTable method should accept a callback that will process the result of its execution.
// Accept a callback as a parameter
getFromTable: function(table, callback) {
this._connection.query('SELECT * FROM '+ table +';', function(err, result) {
if(err)
// execute the callback for a null result and an error.
callback(err, null);
else if( !result )
callback(new Error('Error bij het ophalen van foto\'s'),null);
else
// execute the callback on the result
callback(null, result);
}.bind(this));
}
The method can now be used in this manner:
// This is the callback to be passed into the method.
function processResult(err, result) {
console.log(result);
}
db.getFromTable('photos', processResult);

Related

returning data from node mssql execute functions

I'm using mssql(Microsoft SQL Server client for Node.js) package from npm.I'm trying to execute a stored procedure residing in my sql server database.Everything works fine.However what I want to do is return the recordsets so that i can export this to be used in other module.Below is what I'm trying to do.
function monthlyIceCreamSalesReport (scope){
var connObj = connConfig();
connObj.conn.connect(function(err){
if(err){
console.log(err);
return;
}
connObj.req.input('Month',4);
connObj.req.input('Year',2016);
connObj.req.execute('<myStoredProcedure>', function(err, recordsets, returnValue){
if(err){
console.log(err);
}
else {
console.log(recordsets[0]); // successfully receiving the value
}
connObj.conn.close();
});
});
console.log('check for recordsets', recordsets[0]); // undefined
return recordsets[0];
}
var sqlServerObj = {
monICSalesReport : monthlyIceCreamSalesReport,
};
module.exports = sqlServerObj;
As shown in the code snippet, since the value of recordsets[0] is undefined, exporting this function is of no use.
You can't return this way in async nature. You can get it by passing the callback function
Try to give a callback function like this
function monthlyIceCreamSalesReport(scope, callback) { // pass a callback to get value
var connObj = connConfig();
connObj.conn.connect(function(err) {
if (err) {
console.log(err);
return;
}
connObj.req.input('Month', 4);
connObj.req.input('Year', 2016);
connObj.req.execute('<myStoredProcedure>', function(err, recordsets, returnValue) {
if (err) {
console.log(err);
} else {
console.log(recordsets[0]);
connObj.conn.close();
return callback(null, recordsets[0]); //return as a callback here and get that value in callback from where you called this function
}
});
});
}
var sqlServerObj = {
monICSalesReport: monthlyIceCreamSalesReport,
};
module.exports = sqlServerObj;
Note: See the comment to understand the changes
recordsets[0] is undefinded, because is defined only in connObj.req.execute function scope. You may do this in this way:
function monthlyIceCreamSalesReport (scope, cb){
var connObj = connConfig();
connObj.conn.connect(function(err){
if(err){
console.log(err);
return cb(Error("Something wrong"));
}
connObj.req.input('Month',4);
connObj.req.input('Year',2016);
connObj.req.execute('<myStoredProcedure>', function(err, recordsets, returnValue){
if(err){
console.log(err);
connObj.conn.close();
return cb(Error("Something wrong"));
}
else {
console.log(recordsets[0]); // successfully receiving the value
connObj.conn.close();
return cb(recordsets[0]);
}
});
});
}
var sqlServerObj = {
monICSalesReport : monthlyIceCreamSalesReport,
};
module.exports = sqlServerObj;

Node.js npm mssql function returning undefined

I am using mssql with node.js to connect to an sql server db. I am trying to reduce code by wrapping the connection code in a function with one query parameter. When I call the function from with in a router.get function, it returns undefined.
Any help would be much appreciated.
function sqlCall(query) {
var connection = new sql.Connection(config, function(err) {
if (err) {
console.log("error1");
return;
}
var request = new sql.Request(connection); // or: var request = connection.request();
request.query(query, function(err, recordset) {
if (err) {
console.log("error2");
return;
}
return (recordset);
});
});
}
router code
router.get('/', function(req, res) {
var queryString = "select * from .....";
res.json(sqlCall(queryString));
//sqlCall(queryString)
});
You are trying to treat the sqlCall as a synchronous function with a return value, while the request.query function on the opposite is an asynchronous function, expecting a callback.
Since Node.js uses non blocking IO and callback structures for flow control, using an asynchronous structure based around callbacks is the way to go. In your case this could look like this:
router.get('/', function(req, res) {
var queryString = "selec * from .....";
sqlCall(queryString, function(err, data) {
if (typeof err !== "undefined" && err !== null) {
res.status(500).send({
error: err
});
return;
}
res.json(data);
});
});
with your other component looking like this:
function sqlCall(query, cb) {
var connection = new sql.Connection(config, function(err) {
if (typeof err !== "undefined" && err !== null) {
cb( err );
return
}
var request = new sql.Request(connection); // or: var request = connection.request();
request.query(query, function(err, recordset) {
cb( err, recordset );
});
});
}

Anonymous function and closures in socket.io

I' have this code, know that require anonymus closure function, but don't understand how it works. If I run it there is a TypeError: undefined is not a function.
Can some one explain me anonymus closure functions with the help of this code?
mysql= require('mysql');
var connection = mysql.createConnection({});
function check_auth(input, callback){
var sql = "query to mysql";
connection.query(sql, function(err, results) {
if (err) callback(err);
if (results.length > 0) {
callback(null,results.values); //this is the line with error
}else{
callback(null, false);
}
});
};
var io = require('socket.io').listen(5678);
io.configure(function () {
io.set('authorization', function(req, callback) {
check_auth(req.query.s, function(err, result) {
if (err) {
return console.log('error:(');
}
if(result === false) {
return callback('notauth', false);
} else {
return callback(null, result);;
}
});
});
});
You code looks good, but you have an error in your code: missing ); };
mysql= require('mysql');
var connection = mysql.createConnection({});
function check_auth(input, callback){
var sql = "query to mysql";
connection.query(sql, function(err, results) {
if (err) callback(err);
if (results.length > 0) {
callback(null,results.values); //this is the line with error
}else{
callback(null, false);
}
}); // missing );
}; // missing };
io.configure(function () {
io.set('authorization', function(req, callback) {
check_auth(req.query.s, function(err, result) {
if (err) {
return console.log('error:(');
}
if(result === false) {
return callback('notauth', false);
} else {
return callback(null, result);;
}
});
});
});
There seems to be scoping issue in your code. You can't really call a function from another scope without referencing that scope. if you do:
io.configure(function () {
io.set('authorization', function(req, callback) {
var check_auth = function(...) {}; // <=== local defined
// then you can call this way
check_auth(...);
}
}
Since your check_auth() is defined outside, the callback of io.set() has its own scope, it doesn't know anything about check_auth(). So you have to point to the scope that has check_auth() defined. Something like this:
var me = this; // <==== scope that has check_auth defined
io.configure(function () {
io.set('authorization', function(req, callback) {
// then you can call this way
me.check_auth(...);
}
}
Or you can do closure approach by assigning check_auth to a variable and call it inside the callback. Something like this:
var check_auth = function(...) {};
io.configure(function () {
io.set('authorization', function(req, callback) {
// then you can call this way
check_auth(...);
}
}

How to wait for a response from a mongo findOne query in a node/express app before using the response in following control flow

I am new to node, and also JavaScript callbacks.
I am trying to check if an account exists in mongo and then 'save it' if it doesn't and return an error if it does.
I am currently trying to figure this out outside of my express app. This is what i have..
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/main', function (err, db) {
if(err) throw err;
var query = { name : "www.website.com"}
findOne(db, query, function (doc) {
if(doc) {
console.log('account exists');
} else {
console.log('good to go');
}
console.dir(doc);
});
});
var findOne = function (db, query, callback) {
db.collection('accounts').findOne(query, function (err, doc) {
if(err) throw err;
db.close();
callback();
});
}
with the console.dir(doc); above returning as undefined. How do I wait for the findOne to return before using the callback to console.log or save the account?
The reason you are getting undefined is because when you call your callback your are not passing it the doc. That line should look like callback(doc).
Here is an updated version of your code with a few suggestions:
MongoClient.connect('mongodb://localhost:27017/main', function (err, db) {
if(err) throw err;
var query = { name : "www.website.com"}
findOne(db, query, function (err, doc) {
if(err) {
// something went wrong
console.log(err);
return;
}
if(doc) {
console.log('account exists');
console.dir(doc);
} else {
console.log('good to go');
}
});
});
var findOne = function (db, query, callback) {
db.collection('accounts').findOne(query, function (err, doc) {
db.close();
if(err) {
// don't use throw when in async code
// the convention is to call your callback with the error
// as the first argument (notice that I added an argument
// to the definition of your callback above)
callback(err);
}
else {
// call your callback with no error and the data
callback(null, doc);
}
});
}

How can convert this node.async code to using q? Do I need to return a promise?

In "view" method within my controller was previously using node-async but I wanted to try out using q.
I'm currently trying to convert this
exports.view = function (req, res) {
var category = req.params.category,
id = req.params.id,
ip = req.connection.remoteAddress,
slug = req.params.slug,
submission,
userId = typeof req.session.user !== 'undefined' && req.session.user.id ? req.session.user.id : null,
views;
var getSubmission = function (submissionId, callback) {
Submission.getSubmission({
id: submissionId
}, function (err, submission) {
if (err) {
callback(err);
} else if (submission) {
callback(null, submission);
} else {
callback(err);
}
});
};
async.waterfall([
function (callback) {
getSubmission(id, callback);
},
function (submission, callback) {
res.render('submission', {
title: submission.title + ' -',
submission: submission
});
}]);
To using q... I started doing something like:
var getSubmission = function(id) {
return Submission.getSubmission({
id : submissionId
}).then(function(submission) {
return submission;
});
};
q.fcall(getSubmission).then(function(submission) {
console.log(submission);
});
But it's not quite working as I intended. Am I doing something wrong here? How can I do this?
Is Submission.getSubmission a call to a database? Then you can't "chain" promises to that. You'll have to use the deferred method:
var getSubmission = function(id) {
var deferred = Q.defer();
Submission.getSubmission({
id: id
}, function(err, data){
if (err) {
deferred.reject(err);
} else {
deferred.resolve(data);
}
});
return deferred.promise;
}
getSubmission(some_id).then(successCallback, failureCallback);
You can also use Q#denodeify to convert a function using nodejs-style callbacks (function(err, data)) into a promise based function. Thus, the above can also be achieved by the following:
getSubmissionPromise = Q.denodeify(Submission.getSubmission);
getSubmissionPromise({id: some_id}).then(successCallback, failureCallback);

Categories

Resources