Query is not executed inside of a loop function nodejs MySQL - 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}'

Related

Increment a value on MYSQL with react node.js

Why does this doesn't work
const increment = 'votes + 1'
db.query("UPDATE president SET votes = ? WHERE nickname = ?",
[increment, president], (err, result) => {
if (err) {
console.log(err)
} else {
console.log(result)
}
})
but this code below works
db.query("UPDATE president SET votes = votes + 1 WHERE nickname = ?",
[president], (err, result) => {
if (err) {
console.log(err)
} else {
console.log(result)
}
})
I just want to do the incrementing of mysql columns with votes = ?
I wanted to do it with the votes = ? way. Does anyone know the proper syntax of incrementing a value in mysql with react node js?

Nodejs: Unable to get query results and store in array

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.

Query in Mysql and Node.js

I have this Mysql query that is working fine. However, I need to add 2 more conditions and I'm not sure how to do this.
//index.js
module.exports = {
getHomePage: (req, res) => {
let query ='SELECT Tbl_Email_mensagens.codigo AS Codigo, Tbl_Email_mensagens.mensagem AS Mensagem,Tbl_Email_mensagens.celular AS Celular, cm_custmaster.fullname AS NomeCompleto FROM Tbl_Email_mensagens LEFT JOIN cm_custmaster ON Tbl_Email_mensagens.celular = cm_custmaster.mobile';
// execute query
db.query(query, (err, result) => {
if (err) {
res.redirect('/');
}
res.render('index.ejs', {
title: ""
,players: result
});
});
},
};
I then need to add these 2 conditions:
Where group = '7' and send = '0'
Very thanks!
SELECT Tbl_Email_mensagens.codigo AS Codigo,
Tbl_Email_mensagens.mensagem AS Mensagem,
Tbl_Email_mensagens.celular AS Celular,
cm_custmaster.fullname AS NomeCompleto
FROM Tbl_Email_mensagens
LEFT JOIN cm_custmaster ON Tbl_Email_mensagens.celular = cm_custmaster.mobile
WHERE Tbl_Email_mensagens.`group` = 7
AND Tbl_Email_mensagens.send = 0
Pay attention - the word group is reserved one, so it MUST be wrapped into backticks. But it is more safe to rename it, to some group_number, for example.
Whereas the quotes over the values are excess (you may store them if according field has any string datatype).

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.

Bringing separate asynchronous branches back into one branch again

I am working on a node js app which makes use of the express and mysql libraries.
I have a MySQL user table with the following columns:
auto incrementing primary id
username varchar unique
There is no password, etc.
Other tables include:
room
id
room_name
user_room
id
user_id (FK to user table)
room_id (FK to room table)
details
id
user_room_id (FK to user_room table)
col1
col2
col3
Upon trying to connect to a room, I want the database to try pulling their data for that room.
If the data does not exist, I want to see if the username exists in the user table.
If the username does exist, I want to get their id.
If the username does not exist, I want to add their name to the user table and capture the last inserted id
Once having their id, I want to add a record to the user_room table for that user and then several records to the details table based on the newly inserted id in the user_room table.
I seem to be getting into a tangled web going into so many layers.
This is what my code currently looks like:
socket.on('enter room', function(data, callback){
var sql = "select col1, col2, col3 from room JOIN user_room on room.id = user_room.room_id JOIN user on user_room.user_id = user.id JOIN details on user_room.id = details.user_room_id where username = ?";
db_connection.query(sql, [socket.nickname], function (err, result) {
if (err){
console.log("ENTER ROOM DB ERROR: " + err);
return;
}
if (!result.length){
var sql = "select id from user where name = ?";
db_connection.query(sql, [socket.nickname], function (err, result){
if (err){
console.log("ENTER ROOM, SELECT ID DB ERROR: " + err);
return;
}
if (!result.length){
var sql = "insert into user (name) values (?)";
db_connection.query(sql, [socket.nickname], function(err, result){
if (err){
console.log("ENTER ROOM, INSERT ID DB ERROR: " + err);
return;
}
id = result.insertId;
});
}
else {
id = result[0].id;
}
});
//We need to pull things back into one branch again here
//Using the user id and room id I will insert a record into the user_room table
//Then using the newly inserted id in the user_room table, I need to add records to a details table
}
});
//Send col1, col2, and col3 data back to user
//This section here also needs to be pulled back into one branch again
io.sockets.emit('details', result);
});
It mostly works, but because I branch off in two different ways to get the user id (one if it already exists, and one if I need to insert it), I do not know how to pull it back together again into one branch.
What can I do to pull my code back into one branch again so that I can use the id again? Or, is there a better way of approaching this altogether?
A side question: Can I safely remove the "callback" in my opening function, or should I be using this somewhere in my code? I feel that the emit is like a callback to the client so that I do not need "callback" here.
I took a different approach to get userId on upsert. I used promise to send the room data immediately, if available.
socket.on('enter room', function (data, callback) {
let nickName = '';
let roomId = '';
return bookingDetails(nickName).then((details) => {
if (details.length !== 0) {
return Promise.resolve(details);
} else {
return createRoom(nickName, roomId);
}
}).then((details) => {
io.sockets.emit('details', details);
});
});
function createRoom(nickName, roomId) {
return getUserDetails(nickName).then((userId) => {
return insertUserRoom(userId, roomId); //your function
}).then((userRoomDetails) => {
return insertDetails(userRoomDetails); //your function
});
}
function bookingDetails(nickName) {
let sql = "select col1, col2, col3 from room " +
"JOIN user_room on room.id = user_room.room_id " +
"JOIN user on user_room.user_id = user.id " +
"JOIN details on user_room.id = details.user_room_id where username = ?";
return new Promise((resolve, reject) => {
db_connection.query(sql, [nickName], function (err, details) {
if (err) {
return reject("ENTER ROOM DB ERROR: ");
}
return resolve(details);
});
});
}
function getUserDetails(nickName) {
return new Promise((resolve, reject) => {
let sql = "select id from user where name = ?";
db_connection.query(sql, [nickName], function (err, userDetail) {
if (err) {
return reject(err);
}
if (userDetail === null) { //insert
return createUser(nickName);
}
return userDetail;
}).then((userDetail) => {
return resolve(userDetail.id);
});
});
}
function createUser(nickName) {
return new Promise((resolve, reject) => {
let sql = "insert into user (name) values (?)";
db_connection.query(sql, [nickName], function (err, userDetail) {
if (err) {
return reject(err);
}
return resolve(userDetail);
});
});
}