Nodejs: Unable to get query results and store in array - mysql

this is my code
const mysqlssh = require('mysql-ssh');
var Promise = require('promise');
const startSSHSQLTunnel = () =>{
return mysqlssh.connect(
{
host: 'xxx.xxx.xx.xxx',
user: 'ball',
password: 'r252_bat'
},
{
host: '192.xxx.xxx.xxx',
user: 'portal',
password: 'r252_bat',
database: 'mydb'
}
)
}
exports.getSignupSummary = async() => {
let res = []
let queryStrings = ['SELECT year, WorkWeek, COUNT(*) AS Count from (SELECT YEAR(signed_up) as year, WEEK(signed_up) as WorkWeek from `chatbots` where signed_up is not null) temp_table group by WorkWeek, year',
'SELECT year, WorkMonth, COUNT(*) AS Count from (SELECT YEAR(signed_up) as year, MONTH(signed_up) as WorkMonth from `chatbots` where signed_up is not null) temp_table group by WorkMonth, year',
'SELECT COUNT(*) as count from `chatbots`']
//SELECT COUNT(*) as count from `chatbots`;
getUserData = function(qs, cb) {
startSSHSQLTunnel().then(client => {
client.query(qs,
function(err, results) {
if (err)
return cb(err);
cb(undefined, results);
})});
}
// Usage:
queryStrings.map(x => {
getUserData(x,
function(err, results) {
res.push(results);
}
)
});
console.log(res);
}
I am trying to get the query results and store in an array called "res"
however I am facing the following issues
the results from the callback function can be console.logged but if I store in array and then try to print it out, I see an empty array.
I tried to use async -> await but it was no use
I tried to encapsulate everything in a new promise and then resolve the results but that was no point as I got an empty promise
please advise

You should try something like this:
exports.getSignupSummary = async() => {
let queryStrings = ['SELECT year, WorkWeek, COUNT(*) AS Count from (SELECT YEAR(signed_up) as year, WEEK(signed_up) as WorkWeek from `chatbots` where signed_up is not null) temp_table group by WorkWeek, year',
'SELECT year, WorkMonth, COUNT(*) AS Count from (SELECT YEAR(signed_up) as year, MONTH(signed_up) as WorkMonth from `chatbots` where signed_up is not null) temp_table group by WorkMonth, year',
'SELECT COUNT(*) as count from `chatbots`']
//SELECT COUNT(*) as count from `chatbots`;
getUserData = function(qs, cb) {
startSSHSQLTunnel().then(client => {
client.query(qs, function(err, results) {
if (err) return cb(err);
cb(undefined, results);
});
});
}
// Usage:
const promises = queryStrings.map(x => {
return new Promise((resolve, reject) => {
getUserData(x, function(err, results) {
if (err) reject(err);
resolve(results);
});
});
});
const res = await Promise.all(promises);
console.log(res);
}
This code uses the .map function to create a promise for each of your queries and store it in an array.
Then we use await Promise.all to wait for all the promises to be resolved.

Related

Query is not executed inside of a loop function nodejs MySQL

I am a beginner in NodeJs and I'm trying to run a SQL query inside of a while, but it is not executing the query. I have a function in which I have an array of data from the database, if I got results, I'll save them in 2 arrays, then I declared an auxiliar variable for the while loop. Inside of the while I have to select all the members that have the reference_id in one of the arrays. If I get data, I have to save the data in the 2 arrays again and repeat the operation until there is no data from the database. The problem is that the query and all the operations that are inside of the query are not working and I don't know why.
everything inside of the loop is being executed just the query is the one that is not being executed.
const membersPiramid2 = (request, response) => {
let member_id = request.params.member_id;
let members_ids = [];
let members = [];
let aux = true;
db.query(`SELECT member_id FROM structures WHERE reference_id = '${member_id}'`, (error, results) => {
if (error) throw error;
if (results.length > 0) {
members_ids = results.map(r => r.member_id);
members.push(results);
while (aux) {
db.query(`SELECT member_id FROM structures WHERE reference_id IN ('${members_ids}')`, (err, newMembers) => {
if (err) throw err;
if (newMembers.length > 0) {
members.push(newMembers);
members_ids.length = 0
members_ids = newMembers.map(m => m.member_id)
} else {
aux = false
}
})
}
}
response.send(members);
I tried using promises and async functions but if I use any loop it is still not working
function submembersPiramid(members_ids) {
return new Promise((resolve, reject) => {
db.query(`SELECT member_id FROM structures WHERE reference_id IN ('${members_ids}')`, (err, newMembers) => {
console.log('hola2')
if (newMembers.length > 0) {
resolve(newMembers)
} else {
reject('No data found')
}
})
})
}
const membersPiramid = (request, response) => {
let member_id = request.params.member_id;
let members_ids = [];
let members = [];
let aux = true;
db.query(`SELECT member_id FROM structures WHERE reference_id = '${member_id}'`, (error, results) => {
if (error) throw error;
if (results.length > 0) {
members_ids = results.map(r => r.member_id);
members.push(results);
async function doFunction() {
await submembersPiramid(members_ids).then(response => {
if (response != 'No data found') {
members.push(response);
members_ids.length = 0;
members_ids = response.map(r => r.member_id)
} else {
aux = false;
}
}).then()
}
while(aux){
doFunction()
}
}
response.send(members);
})
}
Any idea why the query does not work in any loop?
Here is the query result
enter image description here
Something like this is likely to be simpler and many times more efficient:
SELECT p.member_id as parent_member_id, c.member_id as child_member_id
FROM structures p
INNER JOIN structures c on c.reference_id = p.member_id
WHERE p.reference_id = '${member_id}'
While we're here, this looks like it would be crazy-vulnerable to sql injection. Sql injection is big deal, so take a few moments to make sure you understand what sql injection is and your platform's mechanism to use prepared statements/parameterized queries.
instead of two queries , you can do it all in one alone
db.query(`SELECT member_id FROM structures WHERE reference_id IN (SELECT member_id FROM structures WHERE reference_id = '${member_id}') UNION SELECT member_id FROM structures WHERE reference_id = '${member_id}'`
, (err, newMembers) => {
if (err) throw err;
if (newMembers.length > 0) {
members.push(newMembers);
members_ids.length = 0
members_ids = newMembers.map(m => m.member_id)
} else {
aux = false
}
})
in case you really want to use nested queries, which in rare occasions it is necessary, you should see the solutions here where the asyncron communicaion is mandatory Nested query in node js using mysql
and when we are at it, you colud always look also this about sql injection up Preventing SQL injection in Node.js
the query to get all member_ids must be
SELECT
member_id
FROM
structures
WHERE
reference_id IN (SELECT
member_id
FROM
structures
WHERE
reference_id = '${member_id}')
UNION SELECT
member_id
FROM
structures
WHERE
reference_id = '${member_id}'

Getting a function out of a query

I'm trying to get a variable out of a query as shown below, thanks in advance
var deutsch_meund_note = "";
connection.query(
'SELECT count(*) as sum FROM noten WHERE id = ? and fach = ?',
[id, "mathe"],
function(error, results, fields) {
if (error) {
console.log("no deutsch_schr for id: "+ id);
} else {
const deutsch_meund_viel = results[0].sum;
connection.query(
'SELECT SUM(note) as sum FROM noten WHERE id = ? and fach = ?',
[id, "deutsch_meund"],
function(error, results, fields) {
const deutsch_meund_insge = results[0].sum;
const deutsch_meund_note = deutsch_meund_insge / deutsch_meund_viel;
//this variable: **var deutsch_meund_note = deutsch_meund_note;**
});
}
});
I need to get the variable out of the "connection.query" function but when I try it like the example above it just says "undefined"

node.js mysql count rows get value

Hi everyone i am using React-Native front end with Node.js with Mysql back end ,
I am counting the number of rows with particular id everything is good in the query, i got the value from the query but i am unable to use the value because it is in the the form of
"res_Count":[{"count(*)":2}] .
function i want it in the string format .
Once check my query and the result
router.get('/get_Following_Count/:user_id', (req, res, next) => {
connection.query("SELECT count(*) FROM followers WHERE followers.follower_id=? ORDER BY id DESC ", [req.params.user_id], (err, results, fields) => {
if (!err) {
// res.send(rows);
following_Count = JSON.parse(JSON.stringify(results));
return res.json({ "status": 200, "error": null, "res_Count": following_Count });
} else {
console.log(err);
return res.status(404).send('Sorry user_id does not exits');
}
})
});
Output:
{"status":200,"error":null,"res_Count":[{"count(*)":2}]}
Please give me any suggestions to change the count(*) value
try to change your query from
"SELECT count(*) FROM followers WHERE followers.follower_id=? ORDER BY id DESC"
to
"SELECT count(*) as followersCount FROM followers WHERE followers.follower_id=? ORDER BY id DESC"
and the use, for example
return res.json({ "status": 200, "error": null, "res_Count": following_Count[0].followersCount });
You could do this inside the route in express
router.get('/get_Following_Count/:user_id', (req, res, next) => {
connection.query("SELECT count(*) FROM followers WHERE followers.follower_id=? ORDER BY id DESC ", [req.params.user_id], (err, results, fields) => {
if (!err) {
// res.send(rows);
// CHANGES
following_Count = JSON.parse(JSON.stringify(results))[0];
-> REPLACE THIS COUNT(FIRST ONE) WITH WHATEVER YOU'D LIKE -> following_Count['count'] = following_Count['count(*)'];
delete following_Count['count(*)'];
//END CHANGES
return res.json({ "status": 200, "error": null, "res_Count": following_Count });
} else {
console.log(err);
return res.status(404).send('Sorry user_id does not exits');
}
})
}
The output will be
{"status":200,"error":null,"res_Count": {"count": 2} }
If you want the array back just delete the [0] and loop through each element and apply the logic of renaming the key

Mysql, Node, query within a query, how to populate property in map function from another query

Firstly, if anyone can edit my question title or question to make more sense, please do.
I have a node/express app making mysql queries with mysql.js. I have a query that looks up a table of questions and then runs a map function on the results. Within that map function, I need to query another table, of answers, corresponding to each record in the questions table. The value I need is the number of answers to that question, ie the number of records in each answers table. I've tried all kinds of different examples, but nothing quite fits my case in a way that makes sense to me. New at Node and Express, and even MySQL so having a hard time picking out quite what to.
I understand that the problem is the async nature of node. getAnswersCount() returns "count" before the query finishes. Below is my code. Need some advice on how to achieve this.
The value 123 is assigned to count just to clarify the trace results.
app.get('/', (req, res) => {
db.query('SELECT * FROM questions LIMIT 0, 100',
(error, results) => {
if (error) throw error;
questions = results.map(q => ({
id: q.id,
title: q.title,
description: q.description,
answers: getAnswersCount( q.id )
}));
res.send( questions );
});
});
const getAnswersCount = ( id ) =>
{
const tableName = 'answers_' + id;
var count = 123;
var sql = `CREATE TABLE IF NOT EXISTS ${tableName}(
id int primary key not null,
answer varchar(250) not null
)`;
db.query( sql,
(error, results) => {
if (error) throw error;
//console.log( 'answers table created!' );
});
sql = `SELECT COUNT(*) AS answersCount FROM ${tableName}`;
db.query( sql,
(error, results) => {
if (error) throw error;
//console.log( count ); // will=123
count = results[0].answersCount;
//console.log( count ); // will = results[0].answerCount
});
// I know this code runs before the query finishes, so what to do?
//console.log( count ); //still 123 instead of results[0].answersCount
return count;
}
EDIT: After attempting various versions of Michael Platt's suggestion in his answer without success, I finally worked out a solution using Express callbacks and a promise, adding the answers values to the questions array afterwards:
app.get( '/', (req, res, next ) => {
db.query('SELECT * FROM questions LIMIT 0, 100',
(error, results) => {
if (error) throw error;
questions = results.map(q => ({
id: q.id,
title: q.title,
description: q.description,
}));
next();
});
}, (req, res ) => {
questions.map( currentElem => {
getAnswersCount( currentElem.id ).then( rowData => {
currentElem.answers = rowData[0].answersCount;
if( currentElem.id == questions.length ) res.send( questions );
});
});
});
const getAnswersCount = ( id ) => {
const tableName = 'answers_' + id;
var sql = `CREATE TABLE IF NOT EXISTS ${tableName}(
id int primary key not null,
answer varchar(250) not null
)`;
db.query( sql,
(error, results) => {
if (error) throw error;
//console.log( 'answers table created!' );
});
sql = `SELECT COUNT(*) AS answersCount FROM ${tableName}`;
return new Promise( ( resolve, reject ) => {
db.query( sql, ( error, results ) => {
if ( error ) return reject( err );
resolve( results );
});
});
}
I'm not sure which database module you are using to connect to and query the database but you could make the method async and then await the response from the query like so:
const getAnswersCount = async ( id ) =>
{
const tableName = 'answers_' + id;
var count = 123;
var sql = `CREATE TABLE IF NOT EXISTS ${tableName}(
id int primary key not null,
answer varchar(250) not null
)`;
var results = await db.query(sql);
sql = `SELECT COUNT(*) AS answersCount FROM ${tableName}`;
var count = db.query(sql)[0].answerCount;
// I know this code runs before the query finishes, so what to do?
//console.log( count ); //still 123 instead of results[0].answersCount
return count;
}
app.get('/', async (req, res) => {
db.query('SELECT * FROM questions LIMIT 0, 100',
(error, results) => {
if (error) throw error;
questions = results.map(q => {
const answerCount = await getAnswersCount( q.id )
return {
id: q.id,
title: q.title,
description: q.description,
answers: answerCount
}
}));
res.send( questions );
});
});
I think that will give you what you want and run correctly but it might require a bit of tweaking. You may need to async the function on the actual route itself as well and await the call for getAnswersCount but that should just about do it.

perform async multiple Mysql queries on Node

I'm using node with Mysql and here's my problem.
I'm trying to add new photos on my database and return it as an array
here is my function :
function addNewPhotos(_id, files) {
var deferred = Q.defer();
var new_photos = []
_.each(files, function (one) {
var data = [
one.path,
_id,
0
]
var sql = 'INSERT INTO photos(photo_link, id_user, isProfil) VALUES (?, ?, ?)';
db.connection.query(sql, data, function (err, result) {
if (err)
deferred.reject(err.name + ': ' + err.message);
var sql = 'SELECT id_user, photo_link, isProfil FROM `photos` WHERE id = ?';
if (result){
db.connection.query(sql, [result.insertId], function(err, photo) {
if (err) deferred.reject(err.name + ': ' + err.message);
if (photo) {
new_photos.push(photo[0]);
}
});
}
})
})
deferred.resolve(Array.prototype.slice.call(new_photos));
return deferred.promise}
The Insert works well but i can't retrieve the results to send them back to the client. (my array is empty)
Thanks.
Always promisify at the lowest level, in this case db.connection.query().
if(!db.connection.queryAsync) {
db.connection.queryAsync = function(sql, data) {
return Q.Promise(function(resolve, reject) { // or possibly Q.promise (with lower case p), depending on version
db.connection.query(sql, data, function(err, result) {
if(err) {
reject(err);
} else {
resolve(result);
}
});
});
};
}
Now the higher level code becomes very simple :
function addNewPhotos(_id, files) {
var sql_1 = 'INSERT INTO photos(photo_link, id_user, isProfil) VALUES (?, ?, ?)',
sql_2 = 'SELECT id_user, photo_link, isProfil FROM `photos` WHERE id = ?';
return Q.all(files.map(function(one) {
return db.connection.queryAsync(sql_1, [one.path, _id, 0]).then(function(result) {
return db.connection.queryAsync(sql_2, [result.insertId]);
});
}));
};
To prevent a single failure scuppering the whole thing, you might choose to catch individual errors and inject some kind of default ;
function addNewPhotos(_id, files) {
var sql_1 = 'INSERT INTO photos(photo_link, id_user, isProfil) VALUES (?, ?, ?)',
sql_2 = 'SELECT id_user, photo_link, isProfil FROM `photos` WHERE id = ?',
defaultPhoto = /* whatever you want as a default string/object in case of error */;
return Q.all(files.map(function(one) {
return db.connection.queryAsync(sql_1, [one.path, _id, 0]).then(function(result) {
return db.connection.queryAsync(sql_2, [result.insertId]);
}).catch(function() {
return defaultPhoto;
});
}));
};
Do the return in your async loop function when all has been done
function addNewPhotos(_id, files) {
var deferred = Q.defer();
var new_photos = [];
var todo = files.length;
var done = 0;
_.each(files, function (one) {
var data = [
one.path,
_id,
0
]
var sql = 'INSERT INTO photos(photo_link, id_user, isProfil) VALUES (?, ?, ?)';
db.connection.query(sql, data, function (err, result) {
if (err)
deferred.reject(err.name + ': ' + err.message);
var sql = 'SELECT id_user, photo_link, isProfil FROM `photos` WHERE id = ?';
if (result){
db.connection.query(sql, [result.insertId], function(err, photo) {
if (err) deferred.reject(err.name + ': ' + err.message);
if (photo) {
new_photos.push(photo[0]);
}
if(++done >= todo){
deferred.resolve(Array.prototype.slice.call(new_photos));
return deferred.promise
}
});
}
else
{
if(++done >= todo){
deferred.resolve(Array.prototype.slice.call(new_photos));
return deferred.promise;
}
}
})
})
}