Nested Query in Nodejs Mysql - mysql

I want to count a line in table that has FOO table.
The following code has a bug which show only the last db_name.
RESULT IS LOOK LIKE THIS:
db_0099,0
db_0099,5
db_0099,10
db_0099,3
Could you please suggest me how to fix the nodejs code?
var mysql = require('mysql');
var sql1 = "SELECT table_schema as db_name from information_schema.tables WHERE table_name = 'FOO' ";
var sql2 = "SELECT COUNT(*) as solution FROM {0}.FOO";
var connection = mysql.createConnection({
host : '$$$$$$$',
user : '$$$$$$$',
password : '$$$$$$$',
});
connection.connect(function(err){
console.log('connected as id ' + connection.threadId);
});
connection.query(sql1, function(err, result) {
if (err) throw err;
for (var i = 0, len = result.length; i < len; i++) {
var db_name = result[i].db_name;
console.log(db_name);
connection.query(sql2.replace("{0}",db_name), function(err, result) {
if (err) throw err;
console.log(db_name+','+result[0].solution); //Here db_name is showed only the last one.
});
};
connection.end();
});

i advice a two step solution to this problem:
use connection pooling
var pool = mysql.createPool({
host : 'xxxxx',
user : 'xxxxx',
password : 'xxxxx',
connectionLimit : 100
});
pool can do auto connection, so don't connect to your db, just
pool.query(sql,function(err,res){})
this way you use one connection for each query, which will be closed automatically after using it.
use async await for asyncronous sequential queries.
for that create a getResult function which returns a promise
function getResult(sql){
return new Promise(function(resolve,reject){
pool.query(sql, function(err, result){
if(err){
reject(err)
}else{
resolve(result)
}
})
})
}
then you can await each query in the loop
pool.query(sql1, async function(err, result) {
if (err) throw err;
for (var i = 0; i < result.length; i++) {
var db_name = result[i].db_name;
console.log(db_name);
var sql = sql2.replace("{0}",db_name)
var res = await getResult(sql)
console.log(db_name+','+res[0].solution); //Here db_name is showed only the last one.
};
pool.end()
});
P.S.: async await is a feature of the upcomming node 8.0.0 release in april. for node 7.x you will have to start your script with a commandline switch
node --harmony-async-await yourscript.js

Have you verify the content of result ?
console.log(result);
If it's okay try this :
solutions = results.map(result => {
let dbName = result.db_name;
let queryResult;
connection.query(sql2.replace("{0}", dbName), function(err, result) {
if (err) {
throw err;
} else {
queryResult = `${db_name}, ${result[0].solution}`
console.log(queryResult);
}
});
return queryResult;
})
console.log(solutions);
However, try to use a ORM or a sql parser for your query !
Try this one :)
https://hiddentao.com/squel/

Related

Node.js executing mysql query after receiving message from mqtt broker

I have a node.js file that subscribes to a topic and upon receiving a published message scans a local mysql db for the most recent entry in a variable named "command". Command values will trigger various responses, but I have left this portion out since my issue is before this.
My mysql query appears to be giving me errors. I am trying to look for the most recent entry of the command column and assign the value to a var command. I thought this code would do the trick:
var sql = 'SELECT command FROM motoron2 ORDER BY id DESC LIMIT 1';
con.query(sql, function (err, result) {
if (err) throw err;
});
console.log(result);
var command = result[1];
console.log(command);
But I am getting the following response which seems to indicate an error in the mysql query:
user#server.domain [bin]# node motorlistener.js
Connected to MYSQL!
Connected to Broker!
{"pulse":1}
1
/home/user/etc/domain/bin/motorlistener.js:62
console.log(result);
^
ReferenceError: result is not defined
at MqttClient.<anonymous> (/home/user/etc/domain/bin/motorlistener.js:62:17)
at MqttClient.emit (events.js:314:20)
at MqttClient._handlePublish (/home/user/node_modules/mqtt/lib/client.js:1277:12)
at MqttClient._handlePacket (/home/user/node_modules/mqtt/lib/client.js:410:12)
at work (/home/user/node_modules/mqtt/lib/client.js:321:12)
at Writable.writable._write (/home/user/node_modules/mqtt/lib/client.js:335:5)
at doWrite (/home/user/node_modules/readable-stream/lib/_stream_writable.js:409:139)
at writeOrBuffer (/home/user/node_modules/readable-stream/lib/_stream_writable.js:398:5)
at Writable.write (/home/user/node_modules/readable-stream/lib/_stream_writable.js:307:11)
at TLSSocket.ondata (_stream_readable.js:718:22)
The full code is below, but does anyone know what is causing this error?
////////////////////////////////////////////////////////////////////////////////
//setup
var mqtt = require('mqtt'); //for client use
const fs = require('fs');
var caFile = fs.readFileSync("/home/user/etc/domain/bin/ca.crt");
var topic = "heartbeat";
var mysql = require('mysql');
var con = mysql.createConnection({
host : 'localhost',
user : 'myuser',
password : 'mypass',
database : 'mydb'
});
var options={
port:8883,
clientId:"yo",
username:"myuser2",
password:"mypassw",
protocol: 'mqtts',
clean:true,
rejectUnauthorized: false,
retain:false,
ca:caFile
};
var client = mqtt.connect("http://dns.org",options);
//mqtt connection dialog
client.on("connect",function(){
console.log("Connected to Broker!");
client.subscribe(topic, {qos:1});
});
//mqtt connection handle errors
client.on("error",function(error){
console.log("Broker Connection Error");
process.exit(1);
});
//database connection
con.connect(function(err) {
if (err) throw err;
console.log("Connected to MYSQL!");
});
//handle incoming messages from broker
client.on('message',function(topic, message, packet){
var raw = ""+message;
console.log(raw);
var obj = JSON.parse(raw);
var pulse = obj.pulse;
console.log(pulse);
var sql = 'SELECT command FROM motoron2 ORDER BY id DESC LIMIT 1';
con.query(sql, function (err, result) {
if (err) throw err;
});
console.log(result);
var command = result[1];
console.log(command);
if (command == 1) {
console.log("command=1");
}
else {
console.log("command not equal to 0");
}
});
I am getting the following response which seems to indicate an error in the mysql query
That's not an error in your MySQL query. It's a null reference error because you're trying to use result outside the callback.
Changing your code to this will work:
var sql = 'SELECT command FROM motoron2 ORDER BY id DESC LIMIT 1';
con.query(sql, function (err, result) {
if (err) {
throw err;
}
// access result inside the callback
console.log(result);
var command = result[0];
console.log(command);
});
Depending on your environment you may be able to re-write your code using promises and async/await to reduce the nested scopes.
To do so, you'd need to turn your callback into a promise and then you can await it, like so:
let sql = 'SELECT command FROM motoron2 ORDER BY id DESC LIMIT 1';
// 1 -- we turn the query into a promise
const queryPromise = new Promise((resolve, reject) => {
con.query(sql, function (queryError, queryResult) {
if (queryError) {
reject(queryError);
}
resolve(queryResult);
});
});
try {
// 2 -- we can now await the promise; note the await
let result = await queryPromise;
// 3 -- now we can use the result as if it executed synchronously
console.log(result);
let command = result[0];
console.log(command);
} catch(err) {
// we can catch query errors and handle them here
}
Putting it all together, you should be able to change the on message event handler to an async function in order to take advantage of the async/await pattern as shown above:
client.on('message', async function(topic, message, packet) {
/* .. you can use await here .. */
});
All above code from #Mike Dinescu works perfectly fine. Just dont forget on the end to close the connection!
Else the runner will hangs after tests have finished.
the full solution:
async function mySqlConnect(dbquery) {
const conn = mysql.createPool({
host: 'localhost',
port: 3306,
user: 'test',
password: 'test',
database: 'test'
}, { debug: true });
// 1 -- we turn the query into a promise
const queryPromise = new Promise((resolve, reject) => {
conn.query(dbquery, function (queryError, queryResult) {
if (queryError) {
reject(queryError);
}
resolve(queryResult);
});
});
try {
// 2 -- we can now await the promise; note the await
let result = await queryPromise;
// 3 -- now we can use the result as if it executed synchronously
//console.log(result);
let command = await result[0];
//console.log(command);
return command;
} catch(err) {
}
finally{
conn.end(function(err) {
if (err) {
return console.log('error:' + err.message);
}
//console.log('Close the database connection.');
});
}
}

Node.js synchronously with mysql query

I am trying to implement a synchronous query in mysql with node.js, I tried several ways and did not succeed
I am new to node.js
I use express.js
connection.js
var mysql = require('mysql');
var connMySql = function() {
return mysql.createConnection({
host : 'localhost',
user : 'root',
password : '******',
database : 'ress'
});
}
module.exports = function() {
return connMySql;
}
DAO.js
function UserDAO(connection){
this._connection = connection();
}
UserDAO.prototype.createUser = function (user, callback){
var sql = "insert into... ";
this._connection.query(sql, function(err, result){
//console.log(result)
//console.log()
if (err){
callback(err,false )
}
if (result){
var newI = result.insertId
var sqlOther = "insert into ..... ";
this._connection.query(sql, function(err, result){
if (err){
callback(err,false )
}else if (result.length > 0){
callback(false, result.insertId)
}
});
}
});
}
I try implements await, async and Promisse(.then) but no success.
What I need to make calls synchronously and return insert id?
thanks
From mysql repo I see that you're missing connection.connect()
connection.js
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '******',
database : 'ress'
});
connection.connect(function(err) {
if (err) throw err;
});
module.exports = connection;
DAO _connection must be closed when it's done with it's job
UserDAO.prototype.createUser = function (user, callback){
var sql = "insert into... ";
this._connection.query(sql, function(err, result){
//console.log(result)
//console.log()
if (err){
callback(err,false )
this._connection.end();
}
if (result){
var newI = result.insertId
var sqlOther = "insert into ..... ";
this._connection.query(sql, function(err, result){
if (err){
callback(err,false )
} else if (result.length > 0){
callback(false, result.insertId)
}
this._connection.end();
});
}
});
}

Add every item of an Array to mysql db

I'm pretty new to Java Script and tried to write a small programm to add users to a database. My problem is, that my programs doesn't add every user ones. It adds the last user as often as there are users in the list. users has more than 2 Objects and all the Objects have all field filled.
for(i = 0; i<users.length; i++)
{
var user = users[i];
console.log(user.lastonline)
pool.getConnection(function(err, connection) {
if (err) throw err;
var quer = connection.query('INSERT INTO users SET `steamid` = '+ connection.escape(user.steamid)+', `name`='+connection.escape(user.name)+', `lastonline`='+connection.escape(user.lastonline)+' ON DUPLICATE KEY UPDATE `name`='+connection.escape(user.name)+', `lastonline`='+connection.escape(user.lastonline)+'', function(err, result) {
connection.release();
});
console.log(quer.sql);
});
}
I tried to rewrite this in a lot of different way, but most time I get something like this:
TypeError: Cannot read property 'steamid' of undefined
for(i = 0; i<users.length; i++)
{
pool.getConnection(function(err, connection) {
console.log(users[i]["steamid"]);
if (err) throw err;
var quer = connection.query('INSERT INTO users SET `steamid` = '+ connection.escape(users[i]["steamid"])+', `name`='+connection.escape(users[i].name)+', `lastonline`='+connection.escape(users[i].lastonline)+' ON DUPLICATE KEY UPDATE `name`='+connection.escape(users[i].name)+', `lastonline`='+connection.escape(users[i].lastonline)+'', function(err, result) {
connection.release();
});
console.log(quer.sql);
});
}
EDIT:
Rest of the programm
var mysql = require('mysql');
var Promise = require("bluebird");
var pool = mysql.createPool({
connectionLimit : 10,
host : 'localhost',
user : 'zar',
password : 'qxLLPa06iEs2Bzsu',
database : 'zar',
socketPath: '/var/run/mysqld/mysqld.sock'
});
pool.on('connection', function (connection) {
console.log("connection made")
});
//my testing users
var users = [];
times = Date.now();
user1 = {steamid:012345678912345658,name:"user1",lastonline:times};
user2 = {steamid:012345678912345628,name:"user2",lastonline:times};
user3 = {steamid:012345678912345618,name:"user3",lastonline:times};
users.push(user1);
users.push(user2);
users.push(user3);
Edit: Fixed to use only one connection.
Previous version was getting a new connection for every user.
You should use Promises:
pool.getConnection((err, connection) => {
if (err) {
console.log(err);
return;
}
var tasks = users.map((user) => {
return new Promise((resolve, reject) => {
if (err) {
return reject(err);
}
var quer = connection.query('INSERT INTO users SET `steamid` = ' + connection.escape(user.steamid) + ', `name`=' + connection.escape(user.name) + ', `lastonline`=' + connection.escape(user.lastonline) + ' ON DUPLICATE KEY UPDATE `name`=' + connection.escape(users.name) + ', `lastonline`=' + connection.escape(users.lastonline) + '', function (err, result) {
if (err) {
return reject(err);
}
resolve(result);
});
});
});
Promise.all(tasks)
.then((results) => {
// Array of results passed in resolve
connection.release();
})
.catch((err) => {
// All errors you reject are catched here
});
});
This should workd but still, you are executing all queries in parallel, which can be pretty aggressive for the DB.
I suggest you to look into bluebird Promise.each for better results.

selects only return partial result

I have around 24k of rows in mysql database. Now using nodejs I would like to query and then store it in json file.
var fs = require('fs');
var mysql = require('mysql');
var connection = mysql.createConnection({
host : '10.1.1.2',
user : 'xxx',
password : 'xxx',
database : 'xxx'
});
connection.connect();
var json = '';
var query = 'SELECT * FROM st_training GROUP BY EndDate ORDER BY StartDate DESC';
var query2 = 'SELECT * FROM st_training WHERE EmployeeID=901 GROUP BY EndDate ORDER BY StartDate DESC';
connection.query(query, function(err, results) {
if (err) { throw err;
}
else {
jsonV = JSON.stringify(results);
console.log(jsonV);
fs.writeFile('table.json', JSON.stringify(results), function (err) {
if (err) throw err;
console.log('Saved!');
});
}
connection.end();
});
I can verify only partial around 600 rows being saved from console.log(jsonV) output or in table.json file.
What could go wrong here? is it there is a max limitation for JSON.stringify ?

ExpressJs render after an action

i'm testing ExpressJs and i have a problem.
var mysql = require('mysql');
var url = require('url');
var connection = mysql.createConnection({
host : 'localhost',
port : '8889',
user : 'root',
password : 'root',
database : 'test'
});
var results = '';
// INIT
exports.init = function(req, res) {
if (req.params.query == 'names') {
getByName(req, res);
} else {
res.send('Erreur');
}
}
getByName = function(req, res) {
currentUrl = url.parse(req.url);
getResult = req.params.suffix.split('+');
for (key in getResult) {
connection.query('SELECT * from testnode WHERE nom = "'+getResult[key]+'"', function(err, rows, fields) {
if (err) throw err;
results += JSON.stringify(rows[0]);
console.log(results);
});
}
res.render('api', {'results' : results});
}
When i go for the first time on the page this one is empty and if i refresh the result appear.
I don't know why the first time the variable "results" are empty so the console.log give me the good result.
Have you got any ideas ?
Thanks a lot :)
You error comes from the mix of a loop and a callback. Node.js is a non blocking IO library : the process doesn't wait for your mysql query to finish to continue to do other stuffs, so the callback with the results is executed (sometime) after the render.
You have multiple options, the one I use is https://github.com/caolan/async or call render once all the callback are done.
Or change your strategy:
getByName = function(req, res) {
currentUrl = url.parse(req.url);
getResult = req.params.suffix.split('+');
connection.query('SELECT * from testnode WHERE nom IN ("' + getResult.join('",") + '")', function(err, rows, fields) {
if (err) throw err;
var results = JSON.stringify(rows); //get all the results
res.render('api', {'results' : results});
});
}