I am trying to build an api using sailsjs that calls stored procedures of a MYSQL database. I decided to decouple the query by adding it to a service so that others functions might be able to call them and use them. Below is what I came up with.
under /api/controller/MySqlController
getAllUsers: function (req, res) {
MySqlSpService.spGetAllUsers(function(err, result){
if(err) return res.serverError(err);
return res.ok(result[1]);
});
},
under /api/services/MYSQLService
var MySqlSpService= {
spGetAllUsers: function(callback) {
Database.query('call userDb.sp_get_all_users(#message, #mystatus)', function (err, results) {
callback(err, results);
}); // end query
}
module.exports = MySqlSpService;
When I hit the api the data is displayed exactly how I thought it would be. But the problem is that when I try to call the spGetAllUsers service and assign to a variable, I get a undefined value.
Like this:
var users = MySqlSpService.spGetAllUsers(function(err, result){
if(err) return res.serverError(err);
return result[1];
});
I believe the problem is with the callbacks but I am not sure how to retrieve the data from the query. I have searched for an answer but I can't seem to find the right search terms that match my problem. Any help would be greatly appreciated Thanks in advance.
Indeed, your problem is about callback and asynchronous code.
The MySqlSpService.spGetAllUsers() function does not return anything, there is no return statement in this method. But it executes a callback function where you have the opportunity to execute code that depends on the SQL query result.
You have to write your code like this because the database query is executed asynchronously.
console.log('This is executed first');
MySqlSpService.spGetAllUsers(function(err, result){
console.log('This is executed when the result of the database query is received');
if(err) return res.serverError(err);
users = result[1];
/**
* Here you can access to the "users" data
* and execute code depending on it
*/
});
console.log('This is executed in second and it is not possible to know the result of the query yet');
Tools like async can help you to organize your asynchronous code. By default, async is available globally in sails.js.
Related
I´m trying to do an asynchronous query in NodeJS but keep getting undefined as a result, my code is:
async function Nuevo_Parametro() {
sqlStr = "select * from Parametros limit 10";
conCasos.query(sqlStr, function(err, Resultado, fields) {
if (err) throw err;
return Resultado;
});
}
Nuevo_Parametro().then(Resultado => {
console.log(Resultado);
});
What am I doing wrong?
Thanks in advance
you're mixing callback styles with Promises. The mysql function does not return a Promise, so you can't concatenate it. It uses a callback style - meaning the "async" part is executed in that callback you provide as a parameter.
What you need to do is wrap it up with a Promise and return that. Something along the lines of the following
function Nuevo_Parametro() {
sqlStr="select * from Parametros limit 10"
return new Promise((resolve, reject) => {
conCasos.query(sqlStr, function(err, Resultado,fields) {
if (err) {
return reject(err)
};
resolve(Resultado);
})
})
}
Nuevo_Parametro().then(Resultado => {
console.log(Resultado)
})
Here we return a promise we're creating, and in the callback query offers, I'm resolving it. I kept the variables and property names as they are for simplicity.
If you're going to use extensively the queries, perhaps it might be tedious to be newing promises everytime, so as it's mentioned in this github ticket you can use a wrapper like this one
or maybe use the native promisify utility as this comment states
const fn = util.promisify(connection.query).bind(connection);
const rows = await fn('SELECT col1, col2 FROM users WHERE email = ?', [email]);
I am currently developing a system where I store custumer's information... One of these information is the custumer's address. To do so, I create two tables in my database: Address and Custumer.
I use the address stored in the custumer table as a foreign key... so far so good. The problem is that I need to first save the address and after get the result id (The id is auto increment) and create the query to save the custumer using that id, but I need to do that at the same function using node, unfortunelly, as I try to do so, I get this error:
'Error: Cannot enqueue Query after invoking quit.'
Below is my code:
this.save = function(connection, object, callback){
let sqlAdress = utilClient.createSaveAdressQuery(object.address);
connection.query(sqlAdress , (error, results) => {
if(error) throw error;
objeto.address.id = results.insertId;
//After that the address is saved, I try to save the client
let sql = utilCliente.createSaveQuery(object);
connection.query(sql, (callback));
})
}
Does anyone know how to help me out? Thanks in advance!
This my callback code:
app.post("/save", function(request, response){
var custumer = request.body;
var connection = dbConnection();
eventoBanco.salvar(connection, custumer, function(error, result){
response.send(result);
if(error != null) console.log(error);
});
connection.end();
});
I think I was able to solve that problem by doing so :
clienteFactoryDAO.alterar(connection, cliente, function(erro, result){
response.send(result);
if(erro != null) console.log(erro);
connection.end();
});
As you can notice now, I close the connection query in the callback passed into the function. MY MISTAKE WAS as the #Himanshusharma nicely pointed: I was closing the connection outside the callback function, and as you know, JavaScript is asynchronous, so it was closing the connection too soon and when I needed one, I got nothing. Thanks in advance and I hope it helps someone at some point
where do i close the mysql connection?
I need to run queries in sequence. I am writing code that looks like this at present:
var sqlFindMobile = "select * from user_mobiles where mobile=?";
var sqlNewUser = "insert into users (password) values (?)";
//var sqlUserId = "select last_insert_id() as user_id";
var sqlNewMobile = "insert into user_mobiles (user_id, mobile) values (?,?)";
connection.connect(function(err){});
var query = connection.query(sqlFindMobile, [req.body.mobile], function(err, results) {
if(err) throw err;
console.log("mobile query");
if(results.length==0) {
var query = connection.query(sqlNewUser, [req.body.password], function(err, results) {
if(err) throw err;
console.log("added user");
var user_id = results.insertId;
var query = connection.query(sqlNewMobile, [user_id, req.body.mobile], function(err, results) {
if(err) throw err;
console.log("added mobile");
//connection.end();
});
});
}
});
//connection.end();
(I am a beginner with node, npm-express and npm-mysql. I have tried searching SO for "express mysql cannot enqueue" to find related questions and have not found them.)
I fixed this problem use this method:
connection.end() in your connection.query function
The fixed code is here
If you're using the node-mysql module by felixge then you can call connection.end() at any point after you've made all of the connection.query() calls, since it will wait for all of the queries to finish before it terminates the connection.
See the example here for more information.
If you're wanting to run lots of queries in series, you should look into the async module, it's great for dealing with a series of asynchronous functions (i.e. those that have a callback).
Maybe the problem is that the mySQL query is executed after the connection is already closed, due to the asynchronous nature of Node. Try using this code to call connection.end() right before the thread exits:
function exitHandler(options, err) {
connection.end();
if (options.cleanup)
console.log('clean');
if (err)
console.log(err.stack);
if (options.exit)
process.exit();
}
//do something when app is closing
process.on('exit', exitHandler.bind(null, {cleanup: true}));
Code adapted from #Emil Condrea, doing a cleanup action just before node.js exits
In my case connection.end was being called in a spot that was hard to notice, so an errant call to connection.end could be the problem with this error
i'm new to NodeJS (duh!).
I know it executes functions asynchronous but I still cannot see what causes this phenomenon:
I am using the express and mysql modules and trying to execute an SQL query based on request parameters. It is supposed to be a simple validation API feature where the server is going to lookup a user in a database by listening on a specific URL for two request parameters (user and passwd).
The problem is that the SQL query always returns an empty object as result when I do this using the request parameters in the query.
However, if i hard code the query and run it outside the app.get(...) I get the desired result! But I need this to work on demand by request...
(I'm not intending to use GET-request later on, this example is for debugging purposes :))
What am i doing wrong here?
Here's my code:
// Server and Mysql setup here
var app = require('express').createServer(),
SERVER_PORT = 8080;
var Client = require('mysql').Client,
client = new Client(),
...
// User, password and database setup here, cropped out from this example //
// ...
function validateUser(user, passwd, callback) {
client.query('SELECT date FROM '+CUSTOMERS_TABLE+' WHERE email="'+user+'" AND passwd="'+passwd+'";',
function selectCb(err, results, fields) {
if (err) {
throw err;
}
console.log(fields);
callback(results);
});
}
app.get('/', function(req, res){
var url_parts = url.parse(req.url, true);
var query = url_parts.query;
if((typeof query[REQ_PARAM_USER] != 'undefined' && typeof query[REQ_PARAM_PASSWD] != 'undefined')
&& (query[REQ_PARAM_USER] != '' && query[REQ_PARAM_PASSWD] != '')) {
validateUser(REQ_PARAM_USER, REQ_PARAM_PASSWD, function(results) {
console.log(results);
});
}
res.end("End")
});
app.listen(SERVER_PORT);
console.log('Server running at port '+SERVER_PORT);
Oh, and by the way, console.log(fields) outputs the correct fields! But why not the results?
You are passing the wrong parameters to validateUser:
validateUser(REQ_PARAM_USER, REQ_PARAM_PASSWD, // ...
What you really want:
validateUser(query[REQ_PARAM_USER], query[REQ_PARAM_PASSWD], // ...
Edit: A few other issues with your code:
You don't have to parse the url. Express does this for you, and the query is available as req.query.
You shouldn't throw in asynchronous code. It will give unexpected results. Instead, stick to the nodejs paradigm of passing (err, results) to all callbacks, and do proper error checking where you can -- i.e., in your verifyUser, pass along the error with the callback and check for errors in your get handler. Either res.send(500) (or something) when you get an error, or pass it along to the express error handler by calling next(err).
validateUser(query[REQ_PARAM_USER], query[REQ_PARAM_PASSWD], function(err, results) {
if(err) {
console.error(err);
res.send(500);
} else {
console.log(results);
res.send(results);
}
});
Never pass query parameters directly to something like an SQL query. Instead, use parameters for your SQL query:
client.query('SELECT date FROM '+CUSTOMERS_TABLE+' WHERE email=? AND passwd=?', [user, passwd], // ...
All examples i've seen were doing a query first and then send to client some info.
If I do a query FIRST and then use results in functions it works:
client.query(
('SELECT * FROM '+TABLES_USERS),
function(err, results, fields) {
var Users = (results);
io.sockets.on('connection', function (socket) {
socket.on('event1', function (data) {
var requser = Users[data];
socket.emit('event2', requser);
});
});
client.end();
});
But now i need to do a query on client's request.
I tried something like this but query doesn't work:
io.sockets.on('connection', function (socket) {
socket.on('event1', function (data) {
console.log('query required'); /*works*/
client.query(
('SELECT * FROM '+TABLES_USERS+' WHERE id_user ='+data),
function(err, results, fields) {
if (err) {throw err; /*doesn't work*/
console.log('error'); /*doesn't work*/ }
console.log('query is done'); /*doesn't work too. so i think query just doesn't work cuz there are no error and no results*/
socket.emit('event2', results);
client.end();
});
});
});
There are some things you are not doing ok (in my opinion) in the example above:
1) You don't ask for login after the client is connected to Socket.IO, instead you check to see if his session contains data that can verify is he's connected.
You should read the article about Express, Socket.IO and sessions., since it explains everything in detail (if you are using Express)
2) I think MongoDB, CouchDB and possibly other databases are better suited for realtime applications than MySQL.
I've solved the problem by using node-mysql-libmysqlclient instead of node-mysql. But if someone knows a way to do a query AFTER client's request in node-mysql, please tell me))