Store mysql query rows in variable for later use - mysql

I'm doing a monitoring system project in which I have Arduino sensors data being sent to a node.js server (thru GET requests) and then stored in a MySQL DB.
Whenvever I successfully send data to the server, it connects to the MySQL DB and queries the last 5 received records to do some processing.
Therefore, I need to store the rows of those 5 records in a variable for later use. Meaning that I have to get rows from a connection.query in a variable.
I read that the fact that I'm not able to do this is because node.js being async. So my questions are:
Is it possible to do the described tasks the way I'm trying?
If not, is there any other way to do so?
I'm not putting the whole code here but I'm running a separated test that also doesn't run properly. Here it is:
var mysql = require('mysql');
var con = mysql.createConnection({
host : "127.0.0.1",
user : "root",
password: "xxxx",
database: "mydb",
port : 3306
});
var queryString = "SELECT id, temp1, temp2, temp3, temp4, level_ice_bank, flow FROM tempdata ORDER BY id DESC LIMIT 5";
con.connect(function(err) {
if (err) throw err;
});
var result_arr = [];
function setValue (value) {
result_arr = value;
}
con.query(queryString, function (err, rows, fields) {
if (err) throw err;
else {
//console.log(rows);
setValue(rows);
}
});
console.log(result_arr);
It logs:
[]
But if I uncomment console.log(rows); it logs what I need to store in the variable result_arr.
Thanks in advance to all.

You're seeing this behaviour because con.query(...) is an asynchronous function. That means that:
console.log(result_arr);
Runs before:
con.query(queryString, function (err, rows, fields) {
if (err) throw err;
else {
//console.log(rows);
setValue(rows);
}
});
(Specifically, the setValue(rows) call)
To fix this in your example, you can just do:
con.query(queryString, function (err, rows, fields) {
if (err) throw err;
else {
setValue(rows);
console.log(result_arr);
}
});
If you want to do more than just log the data, then you can call a function which depends on result_arr from the con.query callback, like this:
con.query(queryString, function (err, rows, fields) {
if (err) throw err;
else {
setValue(rows);
doCleverStuffWithData();
}
});
function doCleverStuffWithData() {
// Do something with result_arr
}

Related

having issues calling a sql stored procedure, SelectById, from express

I'm trying to call a saved stored procedure from SQL in my node app. my server is connected and I am able to execute my selectRandom5 saved proc with no problems.
the issue I am having is when I try to do a getById where I need to declare the #Id input. I've tried a couple of variations of the function with no luck, here are two I've tried.
the error message I get with this is UnhandledPromiseRejectionWarning: RequestError: Incorrect syntax near '?'.
selectById(req, res) {
var theId = req.params.id;
// connect to your database
sql.connect(config, function (err) {
if (err) console.log(err);
// create Request object
var request = new sql.Request();
// query to the database and get the records
request.query("CALL Addresses_SelectById(?)", [theId], function (err, recordset) {
if (err) console.log("connect", err);
// send records as a response
res.send(recordset);
console.log(recordset);
});
});
}
and then there's this other function I've tried, and the error message I get from this is 'Must declare the scalar variable "#Id".'
selectById(req, res) {
var theId = req.params.id;
// connect to your database
sql.connect(config, function (err) {
if (err) console.log(err);
// create Request object
var request = new sql.Request();
// query to the database and get the records
request.query(`SET #Id = ${theId}CALL Addresses_SelectById(#Id)`, function (err, recordset) {
if (err) console.log("connect", err);
// send records as a response
res.send(recordset);
console.log(recordset);
});
});
}
I just want to be able to pass parameters to SQL to be able to create update or get by but so far I haven't been able to figure out the proper way to pass the parameters.
any help would be appreciated! thanks guys
I FOUND IT GUYS!
selectById(req, res) {
var theId = req.params.id;
// connect to your database
sql.connect(config, function (err) {
if (err) console.log(err);
// create Request object
var request = new sql.Request();
// query to the database and get the records
request.input("Id", sql.Int, theId);
request.execute("Addresses_SelectById", function (err, recordset) {
if (err) console.log("connect", err);
// send records as a response
res.send(recordset);
console.log(recordset);
});
});
I changed it to this and it works
Problem 1:
Suggested alternate syntax:
selectById(req, res) {
var theId = req.params.id;
let sql = `CALL Addresses_SelectById(?)`;
connection.query(sql, theId, (error, results, fields) => {
if (error) {
return console.error(error.message);
}
console.log(results[0]);
// Possibly stringify "results" to JSON before sending...
res.send(results);
});
}

How to set up an IF condition within mysql package in node.js

I'm using mysql package for node.js
Studying the documentation did not help me with my question.
I want to make following:
if (SELECT table_field WHERE id = some_value ){
// execute some code
} else{
// execute some code
}
So I want SELECT to return either TRUE or FALSE (like EXISTS operator)
How can I do so with node.js?
After you setup your connection, you'll want to do something like this:
con.connect(function(err) {
if (err) throw err;
console.log("Connected!");
var sql = "SELECT table_field WHERE id = some_value" // setup your query
con.query(sql, function (err, result) { // pass your query
if (err) throw err;
console.log("Result: " + result);
if (result) {
// true logic
}
else
{
// false logic
}
});
});
You can't use the SQL query directly in the IF statement. You need to retrieve the results and then use the results as the boolean value.

Need help understanding async/promises with mysql query

var mysql = require('mysql');
var con = mysql.createConnection({
host: "host",
user: "login",
password: "password",
database: "db"
});
con.connect(function (err) {
if (err) throw err;
console.log("Connected!");
function addTalentPoint(id,amount){
var sql = "SELECT RegValue FROM `Registry` WHERE RegChaId="+id+" AND RegIdentifier='TalentPoints'"
var endingTalentPoint = 0;
con.query(sql, function (err, result) {
if (err) throw err;
console.log("Starting Talent Point: "+result[0].RegValue);
endingTalentPoint = result[0].RegValue + amount
var sql = "UPDATE `Registry` SET RegValue="+endingTalentPoint+" WHERE RegChaId="+id+" AND RegIdentifier='TalentPoints'"
con.query(sql, function (err, result) {
if (err) throw err;
console.log(endingTalentPoint)
});
});
}
function getTalentPoint(id){
var sql = "SELECT RegValue FROM `Registry` WHERE RegChaId="+id+" AND RegIdentifier='TalentPoints'"
con.query(sql, function (err, result) {
if (err) throw err;
console.log("get talent point: "+result[0].RegValue);
});
}
addTalentPoint(4,5)
getTalentPoint(4)
});
My example output:
Starting Talent Point: 125
get talent point: 125
130
I have read through numerous blogs and tried using async / await and setting up promises but I'm not getting where I need to be. I'm trying to get the code to wait for addTalentPoint to finish before getTalentPoint executes. Is it just the nature of the beast that it sends the query off, and then continues on with the code? I could put getTalentPoint inside the callback under the UPDATE, but how can I know the update finished?
addTalentPoint is still doing async stuff - all those con.query calls are async - so unless you do the work in the callbacks, things will just be executed immediately (like your getTalentPoint function) - one solution would be to add a callback function to the addTalentPoint function. See the below changes:
//First, add a callback parameter
function addTalentPoint(id,amount,callback){
...
//next, use this callback when the work is done
if (err) throw err;
console.log(endingTalentPoint)
if (callback) callback(); //if a callback exists, call it
Now, use your new param:
addTalentPoint(4,5, function() {
//All done doing the work in addTalentPoint, lets do more things now!
getTalentPoint(4)
})

Node.js returning result from MySQL query

I have the following function that gets a hexcode from the database
function getColour(username, roomCount)
{
connection.query('SELECT hexcode FROM colours WHERE precedence = ?', [roomCount], function(err, result)
{
if (err) throw err;
return result[0].hexcode;
});
}
My problem is that I am returning the result in the callback function but the getColour function doesn't return anything. I want the getColour function to return the value of result[0].hexcode.
At the moment when I called getColour it doesn't return anything
I've tried doing something like
function getColour(username, roomCount)
{
var colour = '';
connection.query('SELECT hexcode FROM colours WHERE precedence = ?', [roomCount], function(err, result)
{
if (err) throw err;
colour = result[0].hexcode;
});
return colour;
}
but of course the SELECT query has finished by the time return the value in colour
You have to do the processing on the results from the db query on a callback only. Just like.
function getColour(username, roomCount, callback)
{
connection.query('SELECT hexcode FROM colours WHERE precedence = ?', [roomCount], function(err, result)
{
if (err)
callback(err,null);
else
callback(null,result[0].hexcode);
});
}
//call Fn for db query with callback
getColour("yourname",4, function(err,data){
if (err) {
// error handling code goes here
console.log("ERROR : ",err);
} else {
// code to execute on data retrieval
console.log("result from db is : ",data);
}
});
If you want to use promises to avoid the so-called "callback hell" there are various approaches.
Here's an example using native promises and the standard MySQL package.
const mysql = require("mysql");
//left here for testing purposes, although there is only one colour in DB
const connection = mysql.createConnection({
host: "remotemysql.com",
user: "aKlLAqAfXH",
password: "PZKuFVGRQD",
database: "aKlLAqAfXH"
});
(async () => {
connection.connect();
const result = await getColour("username", 2);
console.log(result);
connection.end();
})();
function getColour(username, roomCount) {
return new Promise((resolve, reject) => {
connection.query(
"SELECT hexcode FROM colours WHERE precedence = ?",
[roomCount],
(err, result) => {
return err ? reject(err) : resolve(result[0].hexcode);
}
);
});
}
In async functions, you are able to use the await expression which will pause the function execution until a Promise is resolved or rejected. This way the getColour function will return a promise with the MySQL query which will pause the main function execution until the result is returned or a query error is thrown.
A similar but maybe more flexible approach might be using a promise wrapper package of the MySQL library or even a promise-based ORM.

How to structure Node.js script with MySQL so that connection doesn't close prematurely

So I am making my first attempt with Node and I can't really wrap my head around how to work with the MySQL connection. The script is somewhat simplified like this
var mysql = require('mysql');
var connection = mysql.createConnection({
host : '192.168.40.1',
user : 'user',
password : 'password',
database : 'database'
});
function DoSomething(connection, item, callback) {
connection.query(
'SELECT COUNT(*) AS count FROM another_table WHERE field=?',
item.field,
function (err, results) {
if (err) throw err;
if (results.length > 0 && results[0].count >= 1) {
callback(err, connection, item, 'Found something')
}
});
}
function DoSomethingElse(connection, item, callback) {
// Similar to DoSomething()
}
function StoreResult(err, connection, item, reason) {
if (err) throw err;
connection.query(
'INSERT INTO result (item_id, reason) VALUES (?, ?)',
[item.id, reason],
function (err, results) {
if (err) throw err;
});
}
connection.query('SELECT * FROM table WHERE deleted=?', [0], function (err, results)
{
if (err) throw err;
results.forEach(function (item, index) {
DoSomething(connection, item, StoreResult);
DoSomethingElse(connection, item, StoreResult);
});
});
connection.end();
What I am having trouble with (as far as I can tell) is that since DoSomething() it seems that connection.end() is called before all of the DoSomething()'s have finished causing errors that queries can't be performed when the connection is closed.
I tried playing around with the async library, but I haven't gotten anywhere so far. Anyone with some good advice on how to do this?
The problem with your code is that you're closing the connection synchronously while an asynchronous request is still being handled. You should call connection.end() only after all query callbacks have been called.
Since you are doing multiple queries, this means using some way to wait for all their results. The simplest way is to nest every next call into the callback of the previous one, but that way leads to the pyramid of doom. There are a number of popular libraries that solve this, but my own preference is for async.
Using async I would rewrite your code as follows:
async.waterfall([function(next) {
connection.query('SELECT * FROM table WHERE deleted=?', [0], next); // note the callback
},
function(results, next) {
// asynchronously handle each results. If they should be in order, use forEachSeries
async.forEach(results, function(item, next) {
// handle in parallel
async.parallel([function(done) {
DoSomething(connection, item, function(err, connection, item, reason) {
// This is a hack, StoreResult should have a callback which is called
// after it's done, because the callback is now being called too soon
StoreResult(err, connection, item, reason);
callback(err);
});
}, function(done) {
DoSomethingElse(connection, item, function(err, connection, item, reason) {
// This is a hack, StoreResult should have a callback which is called
// after it's done, because the callback is now being called too soon
StoreResult(err, connection, item, reason);
callback(err);
}], function(err) {
// this callback is called with an error as soon as it occurs
// or after all callbacks are called without error
next(err);
});
}, function(err) {
// idem
next(err);
});
}], function(err, results) {
// idem
// Do whatever you want to do with the final error here
connection.end();
});
This also allows you to solve a possible issue with the order of your queries in the forEach: They are started in order, but are not guaranteed to finish in order due to their asynchronous nature.
Close your connection after you have done everything you want in the script.
When programming in asynchronous language, keep in mind that the real ending point of your script is the last asynchronous callback, instead of the last line like other scripts (e.g. PHP).
Note that you don't want to simply ignore the connection.end(); as the underlying MySQL driver will keep the connection alive and your script will stuck in the last line forever until you kill it.
This is the modified version of your code.
connection.query('SELECT * FROM table WHERE deleted=?', [0], function (err, results)
{
if (err) throw err;
results.forEach(function (item, index) {
DoSomething(connection, item, StoreResult);
DoSomethingElse(connection, item, StoreResult);
});
// End your connection here
connection.end();
});