MySQL querying in NodeJS - mysql

I'm trying to write an app that will check whether or not an webpage has changed.
I'm using NodeJs mysql because I'm familiar with them.
So at the moment, I have the problem that my query is too 'slow', so my function will not return true, even though it should. Can I force my app to wait for the query somehow?
Edit:
checkEntry(webpage, callback) {
var oldPage;
this.mysql.query('SELECT OldWebpagecol FROM Web_Scraping.OldWebpage WHERE idOldWebpage = 15', (err, rows) => {
if (err) console.log(err);
oldPage = rows[0].OldWebpagecol;
if (webpage === oldPage) {
return true;
}
return false;
})
}

You can use async/await when you make a request.
For example,
(async () => {
let response = await fetch(‘/api/users’);
})();

Related

How to implement a map nested MySQL query in Node that populates a property of each element

I've searched this so many ways and can't seem to get a solution that works for me - perhaps because I'm new to JS and the callback "hell" as I've seen it described.
I first run a query that returns a list of results ("FailTypes"), then I want to iterate over each item in the list and add a property ("FailTypeAreaScores") which itself requires another query. I figured the map function would be the best to do this.
Here's the calling function, 1st query:
static async getFailTypes(eq, callback) {
const sql = 'CALL getFailTypes(?)';
db.query(sql, eq, async (err, rows) => {
let result = Object.values(JSON.parse(JSON.stringify(rows)));
let fts = await Promise.all(result[0].map(async ft => {
const newFt = await getFailTypeAreaScores(ft, (err, data) => {return data})
return newFt }));
if (err){
console.log(err.message);
} else {
callback(null, fts);
};
});
};
Here's the nested query:
async function getFailTypeAreaScores(ft, callback){
const sql = 'CALL getFailTypeAreaScores(?);';
db.query(sql, ft.ID, async(err, rows) =>{
let result = Object.values(JSON.parse(JSON.stringify(rows)));
if (err){
console.log(err.message);
} else {
ft.ftas = result[0];
callback(null, ft);
}
});
};
I've tried various methods of promises and callbacks and nothing seems to work. Right now, I'm getting the data back as expected at the {return data} and if I replace that with a {console.log(data)} I can see the new ft with the added property in the console.
However, it doesn't seem to get out of that function and back up to the map to replace the original ft.
So, my resulting callback(null, fts) just returns a list of null.

async function with mysql query won't return query results node.js

I have a function that queries a mysql database with a select query. This is all inside an async function. The query keeps telling me on the return line that it cannot find the variable "rollStatus".
async function PullRollStatus(){
return new Promise((resolve,reject)=>{
var sql = `SELECT * FROM brawlid${brawlID}`
con.query(sql, (error, rows, fields) => {
var rollStatus= []
for (var i in rows) {
rollStatus.push(rows[i].Bakuganrolled)
}
})
console.log(rollStatus)
return rollStatus
})
}
var rolledcheck = await PullRollStatus();
console.log(rolledcheck)
I've never used new Promise before, as async functions are still kind of new to me. I have tried this without the "return new Promise" line and with it, both giving the same result. I have referenced this
async and await on MySQL call in node js and I'm still getting some problems or it might be confusing me more, I don't know. Any help is greatly appreciated. Thanks in advance!
I would have to know a bit more about the database and the value of brawlID, but you don't use return with promises instead you use resolve and reject, also, you are returning a promise, do you don't use async. Here is an edited example. Note I use mysql.format to pass the variable into the query, this will safeguard against code injection.
Also, I would think you would be using a where statement, unless you have a table for each brawlID, but it would make for sense if brawlID is a column in the table. I changed the function to take the value of brawID passed parameter instead of referencing a global variable.
const mysql = require("mysql2/promise");
const mysqlconfig = {
host: "localhost",
user: "youruser",
password: "yourpassword"
database: "yourdb"
multipleStatements: true
};
const con = mysql.createConnection(msqlconfig);
function to (promise) {
return promise
.then(val => [null, val])
.catch(err => [err]);
}
function PullRollStatus(brawlID){
return new Promise((resolve,reject)=>{
let sql = `SELECT * FROM brawlid WHERE brawlID=?`;
mysql.format(sql,brawlID);
con.query(sql, (error, rows, fields) => {
if (error) {
reject(error);
} else {
let rollStatus = [];
for (let row of rows) {
rollStatus.push(row.Bakuganrolled)
}
console.log(rollStatus);
resolve(rollStatus);
}
});
});
}
let brawlIDtoCheck = 1;
let [err,rolledcheck] = await to(PullRollStatus(brawlIDtoCheck));
if (err) {
console.log("encountered err",err);
}
console.log(rolledcheck)

discord.js/node.js make code wait until sql query returns result

I am working on a discord.js bot, and I'm storing a bunch of information on various servers in a database. The problem is, that the code doesn't wait for the database to return the results. In the current situation, I'm trying to check if the server specific prefix checks out.
I tried using async and await at various places, but those didn't work. If I could, I'd rather not use .then(), because I don't really want to put all the commands inside a .then().
const { Client, Attachment, RichEmbed } = require('discord.js');
const client = new Client();
const mysql = require("mysql");
const config = require("./config.json")
var con = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'botdb'
})
client.on("ready", () => {
console.log("I'm ready")
})
client.on("message", message => {
if (message.author.bot) return;
if (message.channel.type === 'dm') return;
let msg = message.content.split(" ");
let command = msg[0];
let prefix;
con.query(`SELECT * FROM serversettings WHERE ServerID = ${message.guild.id}`, (err, rows) => {
if (err) throw err;
prefix = rows[0].Prefix;
console.log(prefix)
})
console.log(`Prefix: ${prefix}, Command: ${command}`)
if (command === `${prefix}examplecommand`) {
//Do something
}
//Other code that uses prefix and command
}
It should log the prefix first, and then the Prefix: ${prefix}, Command: ${command} part, but it does it the other way around, so the examplecommand doesn't work.
Your result is caused by the fact that what's outside your query callback is executed immediately after the call. Keep in mind the mysql module is callback-based.
Possible Solutions
Place the code inside the callback so it's executed when the query is completed.
Wrap the query in a promise and await it.
function getGuild(guildID) {
return new Promise((resolve, reject) => {
con.query(`SELECT * FROM serversettings WHERE ServerID = '${guildID}', (err, rows) => {
if (err) return reject(err);
resolve(rows);
});
});
}
const [guild] = await getGuild(message.guild.id) // destructuring 'rows' array
.catch(console.error);
console.log(guild.prefix);
Use a Promise-based version of a MySQL wrapper, like promise-mysql. You could use it the same way as the code above, without worrying about coding your own Promises.
const [guild] = await con.query(`SELECT * FROM serversettings WHERE serverID = '${message.guild.id}'`)
.catch(console.error);
console.log(guild.prefix);

Why is my AWS Lambda node.js mysql query not returning?

I'm trying to write some external data into some local tables. We'll be looping through an array, writing most of the data in each array element to the main table and the rest to related tables, replacing all the data each time.
I've stripped the code down to the bare bones to show the problem I'm having. The DELETE runs fine, but the INSERT runs only once, and doesn't even return.
I have a screenshot of the output at https://imgur.com/a/zA6Hz8g .
In it, you can see that the code for the DELETE runs fine (ComQueryPacket sent, OkPacket returned) but when it gets to the INSERT, the ComQueryPacket is sent but nothing is returned. And then the code just falls through.
This results in the first row writing successfully, but no subsequent rows get written.
I've tried changing the connection to use pools, but that didn't help either.
Any ideas?
var mysql = require('mysql');
var promise = require('promise');
const con = mysql.createConnection({
<connectionInfo>,
debug: true
});
function connectToDB() {
return new promise((resolve, reject) => {
console.log("IN connectToDB");
con.connect(function(err) {
if (err) {
console.log("ERROR: Could not connect -- " + err);
reject;
}
console.log("Connected!");
resolve();
});
});
}
function deleteExistingMainRow() {
return new promise((resolve, reject) => {
var query = "DELETE FROM my_table";
con.query(query, [],
function(err, result) {
if (err) {
console.log("ERROR in deleteExistingMainRow: " + err);
reject;
}
else {
console.log("DEBUG: Successful delete of main row");
resolve();
}
});
});
}
function writeMainRow(data_row) {
return new promise((resolve, reject) => {
console.log("IN writeMainRow");
var query = 'INSERT INTO my_table SET id = ?';
con.query(query, [data_row.id],
function(err, result) {
console.log("YES we tried to query");
if (err) {
console.log("ERROR in writeMainRow: " + err);
reject(err);
}
else {
console.log("DEBUG: Successful write of main row");
resolve();
}
});
});
}
exports.handler = function(event, context) {
connectToDB().then(function(script) {
deleteExistingMainRow().then(function(script) {
var data = [{ "id": 1 }, { "id": 2 }, { "id": 3 }];
data.forEach(data_row => {
writeMainRow(data_row).then(function(script) {
console.log("DEBUG: Main row written in forEach");
},
function(err) {
if (err) { console.log("ERR"); } process.exit(0);
}());
});
console.log("DEBUG: Hey we're exiting now");
con.commit;
con.end(function(err) {
console.log("Error on con end: " + err);
});
context.done(null, "DONE");
process.exit(0);
});
});
};
Just a few moths ago AWS made Node.js v 8.10 runtime available in lambda.
Which means, you can use async/await and Promises. So, we can rearrange code to something like this:
exports.handler = async (event, context) => {
const dbConnection = await connectToDB();
await deleteExistingMainRow();
const data = [{ "id": 1 }, { "id": 2 }, { "id": 3 }];
// use here for...of loop to keep working with async/await behaviour
for(const data_row of data){
await writeMainRow(data_row);
}
}
Also, you can rewrite your code to use native Promises or async/await functions.
And of course, cover logic on try/catch block, I've skipped them for simplicity.
The reason why your code is not behaving as you expect is because of the asynchronous nature of NodeJS.
Your for_each loop spawns several threads that are going to INSERT the data in your database.
As soon as these threads are started, the rest of the code will execute, starting with console.log("DEBUG: Hey we're exiting now");
So the commit happens before all the INSERT calls are done and, more importantly, you're calling Process.exit() in your code. This terminates the runtime, even before the INSERT can finish.
Call callback() instead as per https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html
Handling your multiple asynchronous writes can be done differently. First, as grynets commented before me, I would strongly suggest to rewrite your code using async/await to make the call easier to read.
Then, you have to understand that each call to writeMainRow will return its own Promise and your code must wait for ALL promises to complete before to commit() and to callback()
Promise.all(...) will do that for you. See the doc at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
try using
INSERT INTO table_name(id) VALUES (?);
I know both your query and the above query works the same. Just give it a Try.
And just make sure your for loop is working properly sending values to the writeMainRow(function). It wouldnt show an error you if pass an empty value and make sure you are not passing the same values in the for loop. And i think you have to pass writeMainRow(data_row.id) rather than writeMainRow(data_row).
Hope this helps.
And one more suggestion if you are updating multiple rows there are options in mysql node library like transactions. Using those functions will be more effective and you can roll back the result if you face error. Other option is to write procedures, in which case you mysql server will bear the computation.

How to promisify a MySql function using bluebird?

Some time ago I decided to switch from PHP to node. In my first projects I didn't want to use any ORM since I thought that I didn't need to complicate my life so much learning another thing (at the moment I was learning node and angular) therefor I decided to use mysql package without anything else. It is important to say that I have some complex queries and I didn't want to learn from sctratch how to make them work using one of the 9000 ORM node have, This is what I've been doing so far:
thing.service.js
Thing.list = function (done) {
db.query("SELECT * FROM thing...",function (err,data) {
if (err) {
done(err)
} else {
done(null,data);
}
});
};
module.exports = Thing;
thing.controler.js
Thing = require('thing.service.js');
Thing.list(function (err,data) {
if (err) {
res.status(500).send('Error D:');
} else {
res.json(data);
}
});
how can I promisify this kind of functions using bluebird ? I've already tried but .... here I am asking for help. This is what I tried
var Thing = Promise.promisifyAll(require('./models/thing.service.js'));
Thing.list().then(function(){})
I have done this way and it is working fine.
const connection = mysql.createConnection({.....});
global.db = Bluebird.promisifyAll(connection);
db.queryAsync("SELECT * FROM users").then(function(rows){
console.log(rows);});
I have never had much luck with promisifyAll and IMO I prefer to handle my internal checks manually. Here is an example of how I would approach this:
//ThingModule
var Promises = require('bluebird');
Things.list = function(params) {
return new Promises(function(resolve, reject) {
db.query('SELECT * FROM thing...', function(err, data) {
return (err ? reject(err) : resolve(data));
});
});
}
//usage
var thinger = require('ThingModule');
thinger.list().then(function(data) {
//do something with data
})
.error(function(err) {
console.error(err);
})
You can also create a function that fires SQL like this :-
function sqlGun(query, obj, callback) {
mySQLconnection.query(query, obj, function(err, rows, fields) {
if (err) {
console.log('Error ==>', err);
// throw err;
return (err, null);
}
console.log(query)
if (rows.length) {
return callback(null, rows);
} else {
return callback(null, [])
}
});
}
Where mySQLconnection is the connection object you get after mysql.createConnection({}).
After that, you can promisify the function and use the promise like below :-
var promisified = Promise.promisify(sqlGun);
promisified(query, {}).then( function() {} );