I want to fill an array outside the function block
app.get('/getpackages/:dateStart/:dateEnd/:limit', function (req, res) {
var xlsSourceFilesRetrievedTsdz = []
var xlsSourceFilesRetrievedSvn = []
var dateStart = req.params.dateStart;
var dateEnd = req.params.dateStart;
var limit = Number(req.params.limit);
let sql = 'SELECT * FROM summary_dz WHERE Start != "" AND Start BETWEEN ? AND ? LIMIT ?'
db.query(sql, [dateStart,dateEnd,limit], function (err, results) {
if (err) throw err;
for (const counter in results) {
xlsSourceFilesRetrievedTsdz.push(results[counter].XlsSourceFile);
}
// console.log(xlsSourceFilesRetrievedTsdz)
});
console.log(xlsSourceFilesRetrievedTsdz)
I want to fill xlsSourceFilesRetrievedTsdz. Whats wrong with what i wrote? I get an emty array. The console.log inside the block in comment gives the wanted result How can the from outside the block?
Doing this should works:
app.get('/getpackages/:dateStart/:dateEnd/:limit', async (req, res) => {
var xlsSourceFilesRetrievedTsdz = []
var xlsSourceFilesRetrievedSvn = []
const promiseQuery = (sql, dateStart, dateEnd, limit) => {
return new Promise((res, rej)=> {
db.query(sql, [dateStart,dateEnd,limit], function (err, results) {
if (err) rej(err);
res(results)
});
})
}
const sql = 'SELECT * FROM summary_dz WHERE Start != "" AND Start BETWEEN ? AND ? LIMIT ?'
const dateStart = req.params.dateStart;
const dateEnd = req.params.dateStart;
const limit = Number(req.params.limit);
const results = await promiseQuery(sql, dateStart, dateEnd, limit)
for (const counter in results) {
xlsSourceFilesRetrievedTsdz.push(results[counter].XlsSourceFile);
}
console.log(xlsSourceFilesRetrievedTsdz)
}
What I do here was wrap the whole thing in a Promise and return it to wait te results.
Related
I want to create an ID for my program. The ID is random, but I must make sure that it not already exists in database. To do so, I search the ID, and if the search result is empty, then the ID passes, but if the search finds something, the process needs to start over.
In PHP I can do this logic for my code:
require('somesqlconnection.php');
$repeat = false;
do {
$id = createId(50); // this is my function for creating random with 50 as length for the string
$result = mysqli_query("SELECT * FROM users WHERE id = '$id'", $conn);
$repeat = mysqli_num_rows($result) > 0;
} while ($repeat);
echo $id;
How can I implement the same logic in node.js that is basically executing in asynchronous?
I tried this but didn't work:
const util = require('util');
const sql = require('../sqlconnection.js');
let repeat = false;
const query = util.promisify(sql.query).bind(sql);
do {
let id = createId(50);
(async () => {
const rows = await query(`SELECT id FROM users WHERE id = '${id}'`);
repeat = rows.length > 0;
})();
} while(repeat);
console.log(id);
You could create a function that returns a promise for a new ID like this:
const util = require('util');
const sql = require('../sqlconnection.js');
sql.queryAsync = util.promisify(sql.query);
async function createNewId() {
const newId = createId(50);
const result = await sql.queryAsync('SELECT id FROM users WHERE id = ?', [newId]);
return !result.length ? newId : createNewId();
}
This returns the new ID, or it calls itself again.
Usage is either with .then():
createNewId().then(newId => {
console.log('found unused ID', newId);
// do something with it
}).catch(err => {
console.log('oops', err);
});
or inside an async function with await:
async function main() {
try {
const newId = await createNewId();
console.log('found unused ID', newId);
// do something with it
} catch (err) {
console.log('oops', err);
}
}
When I try to take the id it takes it as an undefined variable, but if I just do the res.send () there is no problem Well, I can't think of what to do, have I made several attempts during days, any recommendations?
router.get('/products/:id', (req, res) => {
const id = req.params.id;
const idsiguiente = req.params.id + 1;
const idanterior = req.params.id - 1;
var numero_de_articulos = 16;
const iniciar = (id - 1) * numero_de_articulos;
console.log(req.params.id);
conexion.query('SELECT COUNT(*) AS cuenta_productos FROM Products', (error, cuenta_productos) => {
if (error) throw error;
var paginas = cuenta_productos[0]['cuenta_productos'] / numero_de_articulos;
paginas = Math.ceil(paginas);
conexion.query('SELECT * FROM Products limit ?,?', [iniciar, numero_de_articulos], (error, productos) => {
if (error) throw error;
//res.send(productos);
res.render('products', {
products: productos,
id: id,
paginas: 1,
siguiente: idsiguiente,
anterior: idanterior
});
})
})
});
I have some mysql Query's in NodeJs that depends to a above result. Here is my code:
const sms = async function() {
await connection.query('select * from sms where sms.status_id = 2',
(err, rows) => {
if (err) throw err
rows.forEach(row => {
startdate = moment(row.statdate).format('YYYY-MM-DD HH:mm:ss');
enddate = moment(row.enddate).format('YYYY-MM-DD HH:mm:ss');
connection.query('select * from positions where sms_id = "'+row.id+'" and verified is null order by date asc',
(err, rows2) => {
if (err) throw err
rows2.forEach(row2 => {
connection.query('HERE IS A QUERY TO INSERT A REGISTER IN ANOTHER TABLE', data, (err,res) => {
if (err) throw err
console.log(`Inserted ${res.insertId}`);
})
})
}
);
})
}
)
The problem is, that way, I don't have the expected result in the middle query.
How can i do this synchronous?
I try to use Promises, but i don't understand how to do.
In most cases, you should avoid synchronous functions, especially if running server operations.
Rather, I'd recommend using mysql2 and it's promise wrapper.
Then you can do:
const mysql = require('mysql2/promise');
...
// use promise, then, catch
const sms = async function() {
return connection.query('select * from sms where sms.status_id = 2')
.then(([smss]) =>
smss.map(row => {
connection.query('select * from positions where sms_id = "'+row.id+'" and verified is null order by date asc')
.then(([positions]) => positions)) // unwrap array
)
.then(positions =>
positions.map(row => connection.query('...'))
)
.catch(e => {
// process errors
});
};
// or use awaits
const sms = async () => {
let [smss] = await connection.query('select * from sms where sms.status_id = 2');
let positions = await Promise.all(smss.map(row => {
...
});
};
Alternatively, you can use some better SQL queries to simplify the process. Like this:
select *
from sms
join positions on (positions.sms_id = sms.id)
where sms.status_id = 2
and positions.verified is null
order by positions.date
I have previously attempted to wrap this code in callbacks, async what ever the language has to offer. However, I am still getting nowhere.
The problem is, that members remains empty, even though it should be pushed with info.
channels however, works fine.
Weirdly, the
console.log(values);
prints before the
console.log(result);
Interestingly though,
console.log(result)
does have the correct data, but where I do
console.log(members)
it is empty.
I have tested, the query is all correct, it is literally a problem with the pushing and getting the result earlier than it currently is returned (I assumed Promises would mean things would be more in order, but maybe my understanding is wrong).
Here is the full code:
module.exports.controller = (query, helper, cache, Database, mysql, config) => {
return async (req, res) => {
let zone = req.body.zone;
let returning = {};
if(!zone){
return res.json(helper.responseJson(false, 'Missing parameter "zone"'));
}
function teleport_available(channel_name){
if(channel_name.indexOf("Nadaj / UsuĊ") === -1){
return true;
}else{
return false;
}
}
await mysql.query("SELECT * FROM flamespeak_pbot.zones WHERE zone = '"+ zone +"'", async (err, row) => {
if (err) throw err;
row = row[0];
if (row.length == 0) {
return res.json(helper.responseJson(false, "Zone not found."));
} else {
var channelsPromise = new Promise((resolve, reject) => {
const channels = [];
JSON.parse(row.assignGroupAdditional_ch).forEach(additionalCh => {
cache.channelList.filter(channel => channel.cid == additionalCh).forEach(mainCh => {
mainCh.propcache.teleport_available = teleport_available(mainCh.propcache.channel_name);
mainCh.propcache.subchannels = [];
cache.channelList.filter(channel => channel.pid == additionalCh).forEach(subCh => {
subCh.propcache.teleport_available = teleport_available(mainCh.propcache.channel_name);
mainCh.propcache.subchannels.push(subCh);
});
channels.push(mainCh.propcache);
});
});
resolve(channels);
});
var membersPromise = new Promise((resolve, reject) => {
let members = [];
query.serverGroupClientList(row.serverGroupID)
.then(serverGroupList => {
serverGroupList.forEach(member => {
var sql = "SELECT * FROM teamspeak_clientDbList WHERE client_database_id = '" + member.cldbid + "'";
mysql.query(sql, function (err, result) {
if (err) throw err;
console.log(result);
members.push(result);
})
});
})
.then(() => {
console.log(members);
resolve(members);
});
});
}
Promise.all([channelsPromise, membersPromise]).then(function(values) {
console.log(values);
returning = {
'channels' : values[0],
'members' : values[1],
'pbot' : row,
};
res.send(helper.responseJson(true, returning));
});
});
};
};
With respect, your mixture of callbacks, promises, and async / await is very hard to follow. You'd be wise to simplify it. (Or risk having your name cursed by the person who must maintain this code later.)
The callback in your second mysql.query() method is called whenever MySQL wants (whenever the query finishes or fails). But you don't resolve any promise or return from an async method within that callback's code. So, your console.log(result) shows a correct result, but your other code doesn't get access to that result; your Promise.all resolves before that method is called.
Something like this would, in general, be the right thing to do:
var sql =
"SELECT * FROM teamspeak_clientDbList WHERE client_database_id = '" +
member.cldbid + "'";
mysql.query(sql, function (err, result) {
if (err) throw err;
console.log(result);
members.push(result);
resolve (result); // <<< add this line
})
But in your case it probably won't work: your function query.serverGroupClientList() seems to return a Promise. You didn't show us that function, so it's hard to guess how to weave that into your logic.
query.serverGroupClientList(row.serverGroupID)
.then(serverGroupList => {
let members = [];
serverGroupList.forEach(member => {
var sql = "SELECT * FROM teamspeak_clientDbList WHERE client_database_id = '" + member.cldbid + "'";
mysql.query(sql, function (err, result) {
if (err) throw err;
console.log(result);
members.push(result);
})
});
resolve(members);
})
Try this
SELECT * FROM teamspeak_clientDbList
While iterating serverGroupList, the db Query on each element is asynchronous. Hence empty members.
Moreover foreach expects a synchronous function so you will have to use for-loop or for-of to use async-await feature.
var membersPromise = new Promise((resolve, reject) => {
let members = [];
query.serverGroupClientList(row.serverGroupID)
.then(async (serverGroupList) => {
console.log("serverGroupList: ", serverGroupList);
for (let index = 0, arrLen = serverGroupList.length; index < arrLen; index++) {
let member = serverGroupList[index];
var sql = "SELECT * FROM teamspeak_clientDbList WHERE client_database_id = '" + member.cldbid + "'";
await mysql.query(sql, async function (err, result) {
if (err) throw err;
console.log(result);
members.push(result);
});
}
console.log(members);
resolve(members);
});
});
Nested Code can be improved if you write a wrapper function for db queries which returns a promise.
function fireQuery(mysql, query, params = []) {
return new Promise((resolve, reject) => {
return mysql.query(query, params, (err, data) => {
if (err) return reject(err);
return resolve(data);
});
});
}
// ex -1
let rows = await fireQuery(mysql,query,params);
if(rows.length == 0) {} // your code
// ex-2
let member = await fireQuery(mysql,query2,params2);
members.push(member);
I tried to run a function which returns a value back but am getting undefined.
function getMessageId(myId, user){
$query = "SELECT * FROM startMessage WHERE (userFrom = '"+myId+"' AND userTo = '"+user+"') OR (userFrom = '"+user+"' AND userTo = '"+ myId+"')";
connect.query($query, function(error, rows){
sql = rows[0];
console.log(sql);
return sql.id;
})
}
// running the function
msgId = getMessageId(userFrom, userTo);
console.log(msgId);
Now when I tried to console.log the sql I get the expected result like
{
id : 3,
userFrom : 3,
userTo : 1,
type : "normal",
date : "2017-06-25 06:56:34",
deleted : 0
}
But when I console.log the msgId I get undefined. I am doing this on NodeJS, please any better solution?
Short answer, Because its an asynchronous operation.
The outer console.log happens before the getMessageId returns.
If using callbacks, You can rewrite getMessageId as
let msgId
function getMessageId(myId, user, callback){
$query = "SELECT * FROM startMessage WHERE (userFrom = '"+myId+"' AND userTo = '"+user+"') OR (userFrom = '"+user+"' AND userTo = '"+ myId+"')";
return connect.query($query, function(error, rows){
sql = rows[0];
console.log(sql);
callback(sql.id);
})
}
function setMsgId(id) {
msgId = id;
}
And then call it as,
getMessageId(userFrom, userTo, setMsgId);
Further I would suggest you look into Promises.
Which would very well streamline the flow.
Using Promises, getMessageId should look something like
function getMessageId(myId, user){
$query = "SELECT * FROM startMessage WHERE (userFrom = '"+myId+"' AND
userTo = '"+user+"') OR (userFrom = '"+user+"' AND userTo = '"+
myId+"')";
const promise = new Promise((resolve, reject) => {
connect.query($query, function(error, rows){
sql = rows[0];
console.log(sql);
resolve(sql.id);
})
return promise.
}
Post this, You can use it as
getMessageId(myId, user).then((msgId) => console.log(msgId))
create a wrapper for mysql use
// service/database/mysql.js
const mysql = require('mysql');
const pool = mysql.createPool({
host : 'host',
user : 'user',
password : 'pass',
database : 'dbname'
});
const query = (sql) => {
return new Promise((resolve, reject) => {
pool.query(sql, function(error, results, fields) {
if (error) {
console.error(error.sqlMessage);
return reject(new Error(error));
}
resolve(results);
});
});
}
module.exports = { query };
then call from another script with async funcion and await
// another file, with express route example
const db = require('/service/database/mysql.js')
module.exports = async (req, res) => { // <-- using async!
let output = []; // <-- your outside variable
const sql = 'SELECT * FROM companies LIMIT 10';
await db.query(sql) // <-- using await!
.then(function(result) {
output = result; // <-- push or set outside variable value
})
.catch(e => {
console.log(e);
});
// await db.query("next query" ...
// await db.query("next query" ...
// await db.query("next query" ...
res.json(output);
}
This is probably NOT a proper way, and a hack, but sharing for information purpose (you may not like to use this)
Simply use an if else and call the function once inside the query (if true), and call it outside (if false)
if (id != null) {
// Get Details
const query = pool.execute('SELECT * FROM `sometable` WHERE `id` = ?', [id], function(err, row) {
if (err) {
console.log(err)
return
} else {
if (row && row.length) {
// Do Something
}
}
})
} else {
// Do Something
}