multiple dependent mysql queries in nodejs...promise not the answer? - mysql

I have recently learned how to execute promises in order to run three mysql requests synchronously. I'm disappointed, because I'm learning this is not the solution if I want to run the dependent mysql requests in order. For example, the first gets a variable, which is needed for the second:
My nodejs code:
data.used_time = 7;
var sql;
var sesh_save_val;
var mysql = require('mysql');
//Delete whiteboard session
var con = mysql.createPool({
connectionLimit: 15,
host: "xxxx",
user: "xx",
password: "xxxx",
database: "xxxx"
});
var current_min;
new Promise ((resolve,reject) => {
sql = `SELECT minutes FROM Students WHERE sesh_save = (?)`;
con.query(sql, id, function (err, result)
{
if (err) throw err;
current_min = result[0].minutes;
console.log("no error thrown I think..");
console.log("current_min: " + current_min);
});
resolve("did first func");
}).then((val)=> {
console.log(val);
sql = 'UPDATE Students SET minutes = (?) WHERE sesh_save = (?)';
var min_left = current_min - data.used_time;
console.log("used time: " + data.used_time + " ");
console.log("min_left: " + min_left + " " + "id: " + id);
con.query(sql,[min_left, id], function (err, result)
{
if (err) {console.log(err);}
});
return "did second func";
});
The output is only partially what I would expect. It is:
"did first func", "used_time: 0", min_left: NaN, id: whiteboard-xxxxx-xxxx
"did second func"
"current_min: 4299"
And then error on the line with "con.query(sql,[min_left, id], function (err, result)" because min_left did not exist. Why did min_left not exist? Output showed that current_min existed. However, it existed AFTER the first mysql query resolved, which took so long, that we were able to get into the second .then statement while it's still taking it's time with the first sql query, and the second dependent mysql statement wasn't able to process correctly. How do I fix this?
Thanks for any remarks.

You don't really need 2 queries. You will be good to go with:
sql = 'UPDATE Students SET minutes = minutes - (?) WHERE sesh_save = (?)';
con.query(sql,[data.used_time, id], function (err, result)...

Related

Connecting Alexa skill to mysql database using node.js and aws lambda

I am trying to connect my Alexa skill to an Amazon RDS mySQL database using node.js in AWS Lambda. I tested the connection before uploading it to lambda and it worked but when I upload it I get a 'process exited before completing request' or a 'There was a problem with the skills response' error.
'use strict';
const Alexa = require('alexa-sdk');
const APP_ID = 'amzn1.ask.skill.11069fc0-53bc-4cd0-8961-dd41e2d812f8';
var testSQL = 'SELECT weight, height from users where pin=1100';
//=========================================================================================================================================
//Database connection settings
//=========================================================================================================================================
var mysql = require('mysql');
var config = require('./config.json');
// Add connection details for dB
var pool = mysql.createPool({
host : config.dbhost,
user : config.dbuser,
password : config.dbpassword,
database : config.dbname
});
// var dbHeight, dbWeight, dbMuscle, dbExerciseOne, dbExerciseTwo, dbExerciseThree, dbExerciseFour;
var dbResult;
function searchDB(quest) {
pool.getConnection(function(err, connection) {
// Use the connection
console.log(quest);
connection.query(quest, function (error, results, fields) {
// And done with the connection.
connection.release();
// Handle error after the release.
if (!!error) {
console.log('error')
}
else {
console.log(results[0]);
dbResult = results[0];
return dbResult;
console.log(dbResult.height);
}
process.exit();
});
});
};
//searchDB(testSQL);
//=========================================================================================================================================
//TODO: The items below this comment need your attention.
//=========================================================================================================================================
const SKILL_NAME = 'My Application';
const GET_FACT_MESSAGE = "Here's your fact: ";
const HELP_MESSAGE = 'You can say tell me a space fact, or, you can say exit... What can I help you with?';
const HELP_REPROMPT = 'What can I help you with?';
const STOP_MESSAGE = 'Goodbye!';
var name, pinNumber;
//=========================================================================================================================================
//Editing anything below this line might break your skill.
//=========================================================================================================================================
const handlers = {
'LaunchRequest': function () {
if(Object.keys(this.attributes).length === 0){
this.attributes.userInfo = {
'userName': '',
'pinNo': 0
}
this.emit('GetPinIntent');
}
else{
name = this.attributes.userInfo.userName;
pinNumber = this.attributes.userInfo.pinNo;
var sql = "";
//var result = searchDB(sql);
//var uWeight = result.weight;
//var uHeight = result.height;
var speechOutput = 'Welcome ' + name + 'Please select an option: Check My BMI, Create Exercise Plan, Create Meal Plan, Update Height and Weight, Update workout status?';
this.emit(':ask', speechOutput);
}
},
'GetPinIntent': function (){
this.emit(':ask','Welcome to my Application, as this is your first time please say your name followed by your pin. For example, my name is Jason and my pin is zero one zero one');
//this.emit(':responseReady');
},
'RememberNameID': function (){
var filledSlots = delegateSlotCollection.call(this);
this.attributes.userInfo.userName = this.event.request.intent.slots.name.value;
this.attributes.userInfo.pinNo = this.event.request.intent.slots.pin.value;
var speechOutput = 'Welcome ' + this.attributes.userInfo.userName + ' we have stored your Pin Number and we will call you by name next time. Please select an option: BMI or exercise';
this.response.speak(speechOutput);
this.emit(':responseReady');
},
'CheckBMI': function(){
var sql = 'SELECT height, weight FROM users WHERE pin=' + this.attributes.userInfo.pinNo;
var heightWeight = searchDB(sql);
dbHeight = parseInt(heightWeight.height);
dbWeight = parseInt(heightWeight.weight);
var speechOutput = bmiCalculator(dbHeight, dbWeight);
this.emit(':ask', speechOutput);
},
'AMAZON.HelpIntent': function () {
const speechOutput = HELP_MESSAGE;
const reprompt = HELP_REPROMPT;
this.response.speak(speechOutput).listen(reprompt);
this.emit(':responseReady');
},
'AMAZON.CancelIntent': function () {
this.response.speak(STOP_MESSAGE);
this.emit(':responseReady');
},
'AMAZON.StopIntent': function () {
this.response.speak(STOP_MESSAGE);
this.emit(':responseReady');
},
'SessionEndedRequest': function() {
console.log('session ended!');
this.emit(':saveState', true);
}
};
exports.handler = function (event, context, callback) {
var alexa = Alexa.handler(event, context, callback);
alexa.APP_ID = APP_ID;
alexa.dynamoDBTableName = 'fitnessDB';
alexa.registerHandlers(handlers);
alexa.execute();
};
function delegateSlotCollection(){
console.log("in delegateSlotCollection");
console.log("current dialogState: "+this.event.request.dialogState);
if (this.event.request.dialogState === "STARTED") {
console.log("in Beginning");
var updatedIntent=this.event.request.intent;
//optionally pre-fill slots: update the intent object with slot values for which
//you have defaults, then return Dialog.Delegate with this updated intent
// in the updatedIntent property
this.emit(":delegate", updatedIntent);
} else if (this.event.request.dialogState !== "COMPLETED") {
console.log("in not completed");
// return a Dialog.Delegate directive with no updatedIntent property.
this.emit(":delegate");
} else {
console.log("in completed");
console.log("returning: "+ JSON.stringify(this.event.request.intent));
// Dialog is now complete and all required slots should be filled,
// so call your normal intent handler.
return this.event.request.intent;
}
};
function bmiCalculator (userHeight, userWeight ) {
var speechOutput = " ";
var h = userHeight/100;
var calcBMI = 0;
calcBMI = userWeight / (h*h);
calcBMI = calcBMI.toFixed(2);
if (calcBMI < 18.5) {
speechOutput += "Based on your weight of " +weight+ " kilograms and your height of " + height + " metres, your BMI is " +calcBMI+ ". Meaning you are currently underweight.";
speechOutput += " I would advise you to increase your calorie intake, whilst remaining active.";
return speechOutput;
}
else if (calcBMI >=18.5 && calcBMI < 25){
speechOutput += "Based on your weight of " +weight+ " kilograms and your height of" + height + " metres, your BMI is " +calcBMI+ ". Meaning you are currently at a normal weight.";
speechOutput += " I would advise you to stay as you are but ensure you keep a healthy diet and lifestyle to avoid falling above or below this.";
this.response.speak(speechOutput);
return speechOutput;
}
else if (calcBMI >=25 && calcBMI < 29.9){
speechOutput += "Based on your weight of " +weight+ " kilograms and your height of" + height + " metres, your BMI is " +calcBMI+ ". Meaning you are currently overweight.";
speechOutput += " I would advise you to exercise more to fall below this range. A healthy BMI is ranged between 18.5 and 24.9";
this.response.speak(speechOutput);
return speechOutput;
}
else{
speechOutput += "Based on your weight of " +weight+ " kilograms and your height of" + height + " metres, your BMI is " +calcBMI+ ". Meaning you are currently obese.";
speechOutput += " I would advise you to reduce your calorie intake, eat more healthy and exercise more. A healthy BMI is ranged between 18.5 and 24.9";
return speechOutput;
}
};
The code outlines my database connection. I created the connection query as a function as I will need to make varying queries to the database based on the context. Is there a way to create a function within the exports.handler function that will only call the query when needed?
Or are there any other solutions with regards to connecting to the database in such a way.
You are running into multiple issues, without using a Promise or await, your call is running async and you will never get an answer immediately from the RDS for the lambda call. you need to create a function that will wait for an answer before continuing its logic.
The other issue you will run into is the MySQL RDS instance is it running constantly there may be a cold start issue.
The last thing is in the AWS lambda console be sure to allocate enough resources in compute and time to run this function the default 128 mb of memory and the time to run the function can be adjusted to improve performance
Use sync-mysql to make synchronous queries to a mysql database. It worked for me.

Escaping Node.JS MySQL Issues

Im creating a daemon that automatically changes MYSQL table contents randomly around my pages. (wordpress tables)
I have a array of stories that the system will read and then UPDATE the mysql in the tables, and as well update the timestamp on the server.
My code looks like this
//required libraries
fs = require('fs')
var mysql = require('mysql');
var dateFormat = require('dateformat');
var now = new Date();
//mysql table
var connection = mysql.createConnection({
host : 'yomamabinshoppin',
user : 'nonya',
password : 'defineltynonya',
database : 'okbye'
});
connection.connect();
//sitelisting
var sites = [ 'wp_counlwarehouseposts', 'wp_infounlwarehouseposts', 'wp_infowarehouse31posts', 'wp_netunlwarehouseposts', 'wp_netwarehouse31posts', 'wp_orgunlwarehouseposts', 'wp_orgwarehouse31posts', 'wp_stagcomwarehouseposts', 'wp_stagcowarehouseposts', 'wp_staginfwarehouseposts', 'wp_stagnetwarehouseposts', 'wp_stagorgwarehouseposts'];
//select story from catalogue
function ss (id,callback){
fs.readFile('./' + id +'.txt', 'utf8', function (err,data) {
callback(data);
});}
sites.forEach(function(entry) {
ss(Math.floor(Math.random() * 12), function (returnvalue){
fs.writeFile(entry, returnvalue);
connection.query("UPDATE `warehous_wordpress`.`"+entry+"` SET `post_date` = '"+ dateFormat(now, "yyyy-m-d") +" 01:00:01' WHERE `"+entry+"`.`ID` =1", function(err, rows, fields) {
if (err) throw err;
});
fs.appendFile('postlog.log', "UPDATE `warehous_wordpress`.`"+entry+"` SET `post_content` = '"+returnvalue+"' WHERE `"+entry+"`.`ID` = 1" , function (err) {
});
connection.query("UPDATE `warehous_wordpress`.`"+entry+"` SET `post_content` = '"+returnvalue+"' WHERE `"+entry+"`.`ID` = 1", function(err, rows, fields) {
if (err) throw err;
});
});
});
The issue in question here is at the line of
fs.appendFile('postlog.log', "UPDATE `warehous_wordpress`.`"+entry+"` SET `post_content` = '"+returnvalue+"' WHERE `"+entry+"`.`ID` = 1" , function (err) {
});
Where returnvalue is my story, and where entry is the current table name.
Error: ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual th
at corresponds to your MySQL server version for the right syntax to use near 're
frightened can become a safety issue. When designing something to scare visit'
at line 1
The story that it is referring to has the text of this.
SCARE PEOPLE THE RIGHT WAY.
"We always try to scare forward to try to keep the flow going," Travis says. "A lot of times we try to scare further down the path rather than being scared into the wall," which slows the circulation of traffic through the maze.
Plus, where people instinctively move when they're frightened can become a safety issue. When designing something to scare visitors, you have to think about how people will react—and what they might jump into if they leaped backward in terror. "You never really know how bad something is going to scare somebody," Travis explains. "We try to keep the opposite wall clear from any kind of metal props or anything like that."
At first i thought the issue was related to some html in my stories, so i removed ALL of the html in the stories, same issue was happening.
Any advice to how i could fix this?
Thank you.
UPDATE 1
After escaping the variables for the Query, the modified code, still the same parsing issue on the SQL end
//required libraries
fs = require('fs')
var mysql = require('mysql');
var dateFormat = require('dateformat');
var now = new Date();
//mysql table
var connection = mysql.createConnection({
...
});
connection.connect();
//sitelisting
var sites = [ 'wp_counlwarehouseposts', 'wp_infounlwarehouseposts', 'wp_infowarehouse31posts', 'wp_netunlwarehouseposts', 'wp_netwarehouse31posts', 'wp_orgunlwarehouseposts', 'wp_orgwarehouse31posts', 'wp_stagcomwarehouseposts', 'wp_stagcowarehouseposts', 'wp_staginfwarehouseposts', 'wp_stagnetwarehouseposts', 'wp_stagorgwarehouseposts'];
//select story from catalogue
function ss (id,callback){
fs.readFile('./' + id +'.txt', 'utf8', function (err,data) {
callback(data);
});}
sites.forEach(function(entry) {
ss(Math.floor(Math.random() * 12), function (returnvalue){
fs.writeFile(entry, returnvalue);
connection.query("UPDATE `warehous_wordpress`.`"+entry+"` SET `post_date` = '"+ dateFormat(now, "yyyy-m-d") +" 01:00:01' WHERE `"+entry+"`.`ID` =1", function(err, rows, fields) {
if (err) throw err;
});
fs.appendFile('postlog.log', "UPDATE `warehous_wordpress`.`"+ entry + "` SET `post_content` = '"+ mysql.escape(returnvalue) +"' WHERE `"+ entry +"`.`ID` = 1" , function (err) {
});
connection.query("UPDATE `warehous_wordpress`.`"+ entry +"` SET `post_content` = '" + mysql.escape(returnvalue) + "' WHERE `"+ entry +"`.`ID` = 1", function(err, rows, fields) {
if (err) throw err;
});
});
});
You need to always escape your variables correctly.
If your returnvalue is they're then this portion of your query:
SET `post_content` = '" + returnvalue + "' WHERE
will become:
SET `post_content` = 'they're' WHERE
As you can see, this will result into a syntax error at 're
In the worst case this can be used to inject some data into your database. If returnvalue e.g. would be they', ID='1, then your query will be:
SET `post_content` = 'they', ID='1' WHERE
So you always have to escape you values, either using ? or mysql.escape
Using ?? and ?:
connection.query(
"UPDATE `warehous_wordpress`.?? SET `post_content` = ? WHERE ??.`ID` = 1",
[entry, returnvalue, entry] ,
function(err, rows, fields) {});
Using mysql.escapeId and mysql.escape:
connection.query(
"UPDATE `warehous_wordpress`." + mysql.escapeId(entry) +
" SET `post_content` = " + mysql.escape(returnvalue) +
" WHERE " + mysql.escapeId(entry) + ".`ID` = 1",
function(err, rows, fields) {});
I would suggest you to use ? and ??.
Try like below
fs = require('fs');
var mysql = require('mysql');
var dateFormat = require('dateformat');
var async = require('async');
var connection = mysql.createConnection({
...
});
connection.connect();
var sites = [ 'wp_counlwarehouseposts', 'wp_infounlwarehouseposts', ...];
function copyFile(source, target, callback) {
var rs = fs.createReadStream(source);
rs.on('error', callback);
var ws = fs.createWriteStream(target);
ws.on('error', callback);
ws.on('close', callback);
rs.pipe(wr);
}
function updateSite(site, callback) {
copyFile('./' + Math.floor(Math.random() * 12) +'.txt', site, function(err) {
if (err)
return callback(err);
connection.query(
'UPDATE warehous_wordpress.? SET post_date = ? WHERE ?.ID=1',
[site, dateFormat(now, 'yyyy-m-d') + ' 01:00:01', site],
callback
);
});
}
async.eachSeries(sites, updateSite, function (err) { if (err) throw err; });

Node JS MySQL query dependent on another query

In the following code, I have a select query called queryString which retrieves information about some tweets that are already stored in the database. I want to retrieved the hashtags that are mentioned in those tweets so that I show to a user the tweet information along with the its hashtags:
var queryString = 'select Tweet.Label, Tweet.TDate, Tweet.TLink, Author.Lable, Author.ALink from Tweet, Author where Tweet.AuthorID IN (select ID from Author where Lable = ?) AND Author.ID IN (select ID from Author where Lable = ?)';
var query = connection.query(queryString, [term,term], function(err, rows) {
console.log(rows);
//res.write(JSON.stringify(rows));
var tweet = JSON.parse(JSON.stringify(rows));
for(var i in tweet){
res.write("Author: ");
res.write("<a href='" + tweet[i].ALink + "' target='_blank'>" + tweet[i].Lable + "</a> <br/>");
res.write("Date: " + tweet[i].TDate + "<br/>");
res.write("Tweet: " + "<a href='" + tweet[i].TLink + "' target='_blank'>" + tweet[i].Label + "</a> <br/>");
var query1 = connection.query('select Label from Hashtag where ID IN (select HashID from tweethashs where TweetID IN (select ID from Tweet where Label = ?))', [tweet[i].Label], function(err, rows1) {
var tweet1 = JSON.parse(JSON.stringify(rows1));
for(var i in tweet1){
res.write("Hashtag: ");
res.write(tweet1[i].Label);
}
}
);
res.write("<br/><br/>");
}
res.end();
});
What I did is I included a query for the hashtags inside the loop of tweets so that I take the tweet as a parameter for the hashtags query (in where clause). When I run the code, I got the following error:
events.js:154
throw er; // Unhandled 'error' event
^
Error: write after end
at ServerResponse.OutgoingMessage.write (_http_outgoing.js:426:15)
at Query._callback (C:\Users\Nasser\Desktop\Spring Semester\Intelligent Web\
Node JS\SocialSearch.js:58:11)
at Query.Sequence.end (C:\Users\Nasser\Desktop\Spring Semester\Intelligent W
eb\Node JS\node_modules\mysql\lib\protocol\sequences\Sequence.js:96:24)
at Query._handleFinalResultPacket (C:\Users\Nasser\Desktop\Spring Semester\I
ntelligent Web\Node JS\node_modules\mysql\lib\protocol\sequences\Query.js:144:8)
at Query.EofPacket (C:\Users\Nasser\Desktop\Spring Semester\Intelligent Web\
Node JS\node_modules\mysql\lib\protocol\sequences\Query.js:128:8)
at Protocol._parsePacket (C:\Users\Nasser\Desktop\Spring Semester\Intelligen
t Web\Node JS\node_modules\mysql\lib\protocol\Protocol.js:280:23)
at Parser.write (C:\Users\Nasser\Desktop\Spring Semester\Intelligent Web\Nod
e JS\node_modules\mysql\lib\protocol\Parser.js:73:12)
at Protocol.write (C:\Users\Nasser\Desktop\Spring Semester\Intelligent Web\N
ode JS\node_modules\mysql\lib\protocol\Protocol.js:39:16)
at Socket.<anonymous> (C:\Users\Nasser\Desktop\Spring Semester\Intelligent W
eb\Node JS\node_modules\mysql\lib\Connection.js:96:28)
at emitOne (events.js:90:13)
Can someone help me solving this problem
Basically you make several asynchronous db queries in your for loop, but you close your response when the synchronous for loop is ending.So when the db queries end you try to write on an response which is already closed.
var queryString = 'select Tweet.Label, Tweet.TDate, Tweet.TLink, Author.Lable, Author.ALink from Tweet, Author where Tweet.AuthorID IN (select ID from Author where Lable = ?) AND Author.ID IN (select ID from Author where Lable = ?)';
var query = connection.query(queryString, [term,term], function(err, rows) {
console.log(rows);
//res.write(JSON.stringify(rows));
var tweets = JSON.parse(JSON.stringify(rows));
var queries_made = 0;
var queries_success = 0;
tweets.forEach(function(tweet){
connection.query('select Label from Hashtag where ID IN (select HashID from tweethashs where TweetID IN (select ID from Tweet where Label = ?))', [tweet.Label], function(err, rows1) {
res.write("Author: ");
res.write("<a href='" + tweet.ALink + "' target='_blank'>" + tweet.Lable + "</a> <br/>");
res.write("Date: " + tweet.TDate + "<br/>");
res.write("Tweet: " + "<a href='" + tweet.TLink + "' target='_blank'>" + tweet.Label + "</a> <br/>");
var tweet1 = JSON.parse(JSON.stringify(rows1));
for(var j in tweet1){
res.write("Hashtag: ");
res.write(tweet1[j].Label);
}
res.write("<br/><br/>");
queries_success++;
if(queries_made==queries_success)
res.end();
}
);
queries_made++;
})
});
I have added two counter that will track the db queries you requested and the queries that have replied. When those two counters are equal all db transactions and response writes are completed, so you can close the response stream.
Although this is not best practice. You should check the async module or try to use promises with your db queries.
Edit
I changed the code so that the writes occure when the inside queries complete. Be careful now because the order of the writes will not respect the order of the first query but it will write based on what inside query ends first. I must tell you that this is not the best way to accomplish that and you need to read the async module and the promises i told you before. Also take a look at how to mix asynchronous and synchronous operations in javascript!
If you choose to do this by stalling the res.end() you are not sure whether your response will be written in the same order as the tweets are in the array.
The for loop is synchronous but the queries are asynchronous which means they could finish faster than some which started earlier. Which will result theoretically in the writes to happen at random.
What you can use is an async.map.
Basically, instead of that foreach loop you can put something like the following code:
Note: To better understand this first read the async.map code.
//the tweet for which I get the information from DB
var getTweetInfo = function(tweet, callback){
con.query(query, function(err, tweetInformation){
if(err) {
console.log(err);
//with this you are passing the error back into the async.map function. Otherwise it would be lost (Bad javascript :P)
callback("Error getting tweets" + err);
}
else{
//in here you can make any changes to the tweet information before sending it as a response
//this will send the tweetInformation into the results array
callback(null, tweetInformation);
}
});
}
//tweetsArray is the array with tweets
//getTweeetInfo is a function that will get each tweet from the tweets array and will apply the query to it
async.map(tweetsArray, getTweetInfo, function(error, tweetInformationArray){
if (error) {
console.log(error);
}else{
//'results' will hold an array with the information for each tweet in the same order as the initial tweets
res.json({
response: tweetInformationArray
});
}
})
After this you can parse the response on the front-end. The data is consisted, asynchronous (you do not keep the event loop waiting), in order which means you can go through it and display it nicely on the screen.

Nodejs MySQL ER_PARSE_ERROR on VALID query

I've tried using mysql lib with nodejs and a simple query like SELECT * FROM table; works, but now that I've tried to construct a real query to update my database it doesn't work.
I have used an online validating tool and it checks out.
var mysql = require('mysql');
var request = require('request');
request.get('http://localhost:8080/dump/asda.dump', function (error, response, body) {
if (!error && response.statusCode == 200) {
var data =JSON.parse(body);
var products = data['products'][0];
var myquery = "INSERT INTO `products2` (";
var midquery = ") VALUES (";
for (var k in products) {
if (typeof products[k] === 'number') var v = products[k];
else if (typeof products[k] === 'string') var v = "\'" + products[k]+ "\'";
else if (typeof products[k] === 'boolean') var v = products[k];
else continue;
myquery = myquery + "`" + k + "`,";
midquery = midquery + v + ",";
}
myquery = myquery.slice(0,-1);
midquery = midquery.slice(0, -1);
print(myquery + midquery + ")");
connection.connect();
connection.query(myquery, function (err, rows, fields) {
if (!err) console.log(rows);
else console.log(err);
});
connection.end();
}
});
I have tried both the version with the ticks and without the ticks an none of them work.
Possible reasons might be
Too long query. Maybe some internal char limit exeeded?
Unsupporded characters. I am pretty sure I have quite a few Croatian ćčćš in there. How to I support that?
Improper ' " escaping (although it seems ok to me).
I have 'code' as a table column. I've checked and it's not a reserved keyword in mysql but it's blued in MySQL Workbench so maybe it breaks things somehow.
What I get is:
{ [Error: ER_PARSE_ERROR: You have an error in your SQL syntax; check the
manual that corresponds to your MySQL server version for the right syntax to
use near '' at line 1]
code: 'ER_PARSE_ERROR',
errno: 1064,
sqlState: '42000',
index: 0 }
You should try with the ticks whenever you are using the database entities inside the query like the table names or database variables. As far as your query is concerned, only myquery is getting into the function as your database statement and it doesn't contain the whole query. As a result you are getting an error because of your incomplete complete query and improper syntax in it(as it is incomplete already). Your print statement will print it right because of the concatenation that you have used. If you are able to keep the concatenated query string in a variable such as:
var new_query=myquery + midquery + ")";
And then using it as
connection.query(new_query, function (err, rows, fields) {
if (!err) console.log(rows);
else console.log(err);
});
I think your query should work. Thank you...!

How to pass parameters to mysql query callback in nodejs

I'm trying to figure out the correct way of passing custom data to a query call to be made available in the callback.
I'm using MySQL library in nodejs (all latest versions).
I have a call to connection.query(sql, function(err, result) {...});
I couldn't find a way to 1) pass custom data/parameter to the call so that 2) it can be made available when the callback is invoked.
So what is the proper way of doing so?
I have the following (pseudo-code):
...
for (ix in SomeJSONArray) {
sql = "SELECT (1) FROM someTable WHERE someColumn = " + SomeJSONArray[ix].id;
connection.query(sql, function (err, result) {
...
var y = SomeJSONArray[ix].id;
};
}
From the code above, I need to be able to pass the current value of "ix" used in the query to the callback itself.
How do I do that?
If you are using node-mysql, do it like the docs say:
connection.query(
'SELECT * FROM table WHERE id=? LIMIT ?, 5',[ user_id, start ],
function (err, results) {
}
);
The docs also have code for proper escaping of strings, but using the array in the query call automatically does the escaping for you.
https://github.com/felixge/node-mysql
To answer the initial question with a complete answer/example to illustrate, wrap the callback with an anonymous function which immediately creates a scope containing a "snapshot" if you will of the data passed in.
var ix=1;
connection.query('SELECT 1',
(function(ix){
return function(err, rows, fields) {
console.log("ix="+ix);
console.log(rows);
};
})(ix));
For those new to this concept as I was 20 minutes ago, the last })(ix)); is the outer var ix=1 value which is passed into (function(ix){. This could be renamed (function(abc){ if you changed the console.log("ix="+abc);
fwiw (Thanks Chris for the link which filled in the blanks to arrive at a solution)
While it is OK to pass variables or objects to a mysql query callback function using the tactic described earlier -- wrapping the callback function in an anonymous function -- I think it is largely unnecessary, and I'll explain why with an example:
// This actually works as expected!
function run_query (sql, y) {
var y1 = 1;
connection.query (sql, function (error, rows, fields) {
if (! error)
{
var r = rows[0];
console.log ("r = " + r[1]);
console.log ("x = " + x);
console.log ("y = " + y);
console.log ("y1= " + y);
console.log ("");
}
else
{
console.log ("error = " + error);
}
});
};
var x = 5;
console.log ("step 1: x = " + x);
run_query ("SELECT 1", x);
x = x + 1;
console.log ("step 2: x = " + x);
run_query ("SELECT 1", x);
x = x + 1;
console.log ("step 3: x = " + x);
Produces the following output:
step 1: x = 5
step 2: x = 6
step 3: x = 7
r = 1
x = 7
y = 5
y1= 5
r = 1
x = 7
y = 6
y1= 6
The fear is that the second call to run_query() will overwrite the variable y and/or y1 before the first call to run_query() has a chance to invoke its callback function. However, the variables in each instance of the called run_query() function are actually isolated from each other, saving the day.
MySQL con.query has overloaded function. Inside of callback you use global variable or any variable that is passed into your function parameter. For example:
Example 1: it takes sql string and callback function
var adr = 'Mountain 21';
var sql = 'SELECT * FROM customers;
con.query(sql, function (err, result) {
if (err) throw err;
console.log(adr);
});
Example 2: it takes sql string, parameter and callback function
var adr = 'Mountain 21';
var sql = 'SELECT * FROM customers WHERE address = ?';
con.query(sql, [adr], function (err, result) {
if (err) throw err;
console.log(adr);
});