I have a function that queries SQL to get a string called Prefix.
function getPrefix(Guild) {
let query = "SELECT Prefix FROM Guilds WHERE GuildId=?";
Connection.query(query, [Guild.id], (err, result) => {
if (err) throw err;
return result[0].GuildPrefix;
});
};
Whenever I print the Prefix out (console.log(result[0].Prefix);), it logs it fine - however, whenever I return it and then attempt to call the function, it always returns undefined.
I am using Node JS Version 10.15.1 & I am using MariaDB Version 10.1.37 on the Raspbian stretch of Debian. Please comment if I have left any other information out. Thanks.
In Nodejs the functions related to mysql are always asynchronous which means they will either not return anything or will retuen undefined.
So the solution is to use a callback function.
Eg.
function getPrefix(Guild, callback) {
let query = "SELECT Prefix FROM Guilds WHERE GuildId=?";
Connection.query(query, [Guild.id], (err, result) => {
if (err){
callback(JSON.stringify(err));
};
callback(JSON.stringify(result));
});
};
Related
In the code
var stuff_i_want = '';
stuff_i_want = get_info(parm);
And the function get_info:
get_info(data){
var sql = "SELECT a from b where info = data"
connection.query(sql, function(err, results){
if (err){
throw err;
}
console.log(results[0].objid); // good
stuff_i_want = results[0].objid; // Scope is larger than function
console.log(stuff_i_want); // Yep. Value assigned..
}
in the larger scope
stuff_i_want = null
What am i missing regarding returning mysql data and assigning it to a variable?
============ New code per Alex suggestion
var parent_id = '';
get_info(data, cb){
var sql = "SELECT a from b where info = data"
connection.query(sql, function(err, results){
if (err){
throw err;
}
return cb(results[0].objid); // Scope is larger than function
}
==== New Code in Use
get_data(parent_recording, function(result){
parent_id = result;
console.log("Parent ID: " + parent_id); // Data is delivered
});
However
console.log("Parent ID: " + parent_id);
In the scope outside the function parent_id is null
You're going to need to get your head around asynchronous calls and callbacks with javascript, this isn't C#, PHP, etc...
Here's an example using your code:
function get_info(data, callback){
var sql = "SELECT a from b where info = data";
connection.query(sql, function(err, results){
if (err){
throw err;
}
console.log(results[0].objid); // good
stuff_i_want = results[0].objid; // Scope is larger than function
return callback(results[0].objid);
})
}
//usage
var stuff_i_want = '';
get_info(parm, function(result){
stuff_i_want = result;
//rest of your code goes in here
});
When you call get_info this, in turn, calls connection.query, which takes a callback (that's what function(err, results) is
The scope is then passed to this callback, and so on.
Welcome to javascript callback hell...
It's easy when you get the hang of it, just takes a bit of getting used to, coming from something like C#
I guess what you really want to do here is returning a Promise object with the results. This way you can deal with the async operation of retrieving data from the DBMS: when you have the results, you make use of the Promise resolve function to somehow "return the value" / "resolve the promise".
Here's an example:
getEmployeeNames = function(){
return new Promise(function(resolve, reject){
connection.query(
"SELECT Name, Surname FROM Employee",
function(err, rows){
if(rows === undefined){
reject(new Error("Error rows is undefined"));
}else{
resolve(rows);
}
}
)}
)}
On the caller side, you use the then function to manage fulfillment, and the catch function to manage rejection.
Here's an example that makes use of the code above:
getEmployeeNames()
.then(function(results){
render(results)
})
.catch(function(err){
console.log("Promise rejection error: "+err);
})
At this point you can set up the view for your results (which are indeed returned as an array of objects):
render = function(results){ for (var i in results) console.log(results[i].Name) }
Edit
I'm adding a basic example on how to return HTML content with the results, which is a more typical scenario for Node. Just use the then function of the promise to set the HTTP response, and open your browser at http://localhost:3001
require('http').createServer( function(req, res){
if(req.method == 'GET'){
if(req.url == '/'){
res.setHeader('Content-type', 'text/html');
getEmployeeNames()
.then(function(results){
html = "<h2>"+results.length+" employees found</h2>"
html += "<ul>"
for (var i in results) html += "<li>" + results[i].Name + " " +results[i].Surname + "</li>";
html += "</ul>"
res.end(html);
})
.catch(function(err){
console.log("Promise rejection error: "+err);
res.end("<h1>ERROR</h1>")
})
}
}
}).listen(3001)
Five years later, I understand asynchronous operations much better.
Also with the new syntax of async/await in ES6 I refactored this particular piece of code:
const mysql = require('mysql2') // built-in promise functionality
const DB = process.env.DATABASE
const conn = mysql.createConnection(DB)
async function getInfo(data){
var sql = "SELECT a from b where info = data"
const results = await conn.promise().query(sql)
return results[0]
}
module.exports = {
getInfo
}
Then, where ever I need this data, I would wrap it in an async function, invoke getInfo(data) and use the results as needed.
This was a situation where I was inserting new records to a child table and needed the prent record key, based only on a name.
This was a good example of understanding the asynchronous nature of node.
I needed to wrap the all the code affecting the child records inside the call to find the parent record id.
I was approaching this from a sequential (PHP, JAVA) perspective, which was all wrong.
Easier if you send in a promise to be resolved
e.g
function get_info(data, promise){
var sql = "SELECT a from b where info = data";
connection.query(sql, function(err, results){
if (err){
throw err;
}
console.log(results[0].objid); // good
stuff_i_want = results[0].objid; // Scope is larger than function
promise.resolve(results[0].objid);
}
}
This way Node.js will stay fast because it's busy doing other things while your promise is waiting to be resolved
I've been working on this goal since few weeks, without any result, and I finally found a way to assign in a variable the result of any mysql query using await/async and promises.
You don't need to understand promises in order to use it, eh, I don't know how to use promises neither anyway
I'm doing it using a Model class for my database like this :
class DB {
constructor(db) {
this.db = db;
}
async getUsers() {
let query = "SELECT * FROM asimov_users";
return this.doQuery(query)
}
async getUserById(array) {
let query = "SELECT * FROM asimov_users WHERE id = ?";
return this.doQueryParams(query, array);
}
// CORE FUNCTIONS DON'T TOUCH
async doQuery(queryToDo) {
let pro = new Promise((resolve,reject) => {
let query = queryToDo;
this.db.query(query, function (err, result) {
if (err) throw err; // GESTION D'ERREURS
resolve(result);
});
})
return pro.then((val) => {
return val;
})
}
async doQueryParams(queryToDo, array) {
let pro = new Promise((resolve,reject) => {
let query = queryToDo;
this.db.query(query, array, function (err, result) {
if (err) throw err; // GESTION D'ERREURS
resolve(result);
});
})
return pro.then((val) => {
return val;
})
}
}
Then, you need to instantiate your class by passing in parameter to constructor the connection variable given by mysql. After this, all you need to do is calling one of your class methods with an await before. With this, you can chain queries without worrying of scopes.
Example :
connection.connect(function(err) {
if (err) throw err;
let DBModel = new DB(connection);
(async function() {
let oneUser = await DBModel.getUserById([1]);
let allUsers = await DBModel.getUsers();
res.render("index.ejs", {oneUser : oneUser, allUsers : allUsers});
})();
});
Notes :
if you need to do another query, you just have to write a new method in your class and calling it in your code with an await inside an async function, just copy/paste a method and modify it
there are two "core functions" in the class, doQuery and doQueryParams, the first one only takes a string as a parameter which basically is your mysql query. The second one is used for parameters in your query, it takes an array of values.
it's relevant to notice that the return value of your methods will always be an array of objects, it means that you'll have to do var[0] if you do a query which returns only one row. In case of multiple rows, just loop on it.
I've had this problem before twice. The first time, it was because the returned object was actually an unfulfilled promise, and I was able to get around it by throwing all my code inside of the block so that it would execute in there. Not exactly an ideal solution but it worked and I was in a hurry.
The second time I was using pg-promise instead of just pg, and when this issue popped up I thought "it must be that damn promise again", so instead of tearing my hair out I just uninstalled pg-promise and went with the regular postgres package for nodejs instead. Well, the problem is still here and I'm tearing my hair out.
I'm making an API. I have a controller with functions such as getPayment and postPayment and so on. At some point in these functions, I need to get information from or into the database. In another file, which I called postgres.js, I have a connection to the database and then functions which I can call to insert data, select, etc.
Here is postgres.js as it is right now (this works but only for printing to console):
module.exports = {
select: select
};
const { Client } = require('pg');
const client = new Client({
user: 'myUser',
host: 'localhost',
database: 'myDB',
password: 'myPassword',
port: 5432,
});
client.connect();
function select(){
client.query('SELECT * FROM payments', (err, res) => {
console.log(err ? err.stack : res.rows[0].id);
client.end();
});
}
As you can see right now all it does is get the payments from the table and print a value (in this case, the first row's id) to console.
Here is the code that calls this function, from the controller (payments.js):
var pg = require('../../config/postgres.js')
...
function getPaymentInfo(params){
// get info from the DB
// disregard the fact that I'm not sending any params right now, this is for testing
var result = pg.select();
console.log(result);
console.log(typeof result);
}
Calling pg.select() does in fact activate the select function on postgres.js (and the console log correctly prints the data in res.rows[0].id) however when I try putting a return res.rows[0].id there in order to actually return the information that was retrieved from the database, what comes back into the var result is "undefined" according to the console. Here are a few examples of things I've tried to do to get the data out:
function select(){
var i = '';
client.query('SELECT * FROM payments', (err, res) => {
//console.log(err ? err.stack : res.rows[0].id);
i = err? err.stack : res.rows[0].id;
client.end();
});
return i;
}
I tried this with and without commenting the console.log line, either way it doesn't work.
function select(){
client.query('SELECT * FROM payments', (err, res) => {
//console.log(err ? err.stack : res.rows[0].id);
return res.rows[0].id;
//client.end();
});
}
I figure this would be wrong since I'm returning without checking for an error, but I tried just to see what would happen... undefined again.
function select(){
client.query('SELECT * FROM payments', (err, res) => {
//console.log(err ? err.stack : res.rows[0].id);
return err ? err.stack : res.rows[0].id;
//client.end();
});
}
This time checking for err, still returns undefined.
function select(){
return client.query('SELECT * FROM payments', (err, res) => {
//console.log(err ? err.stack : res.rows[0].id); // Hello World!
client.end();
return err ? err.stack : res.rows[0].id;
});
}
Returning the return from client.query(etc etc);.. same thing as before. Also tried without the explicit return, without checking for error, all the same.
Here's the last test I tried:
function select(){
var i = 'original i';
client.query('SELECT * FROM payments', (err, res) => {
console.log(err ? err.stack : res.rows[0].id); // Hello World!
if (err){
i = "i has changed!";
} else {
i = "i has not changed!";
}
client.end();
});
return i;
}
The console shows this:
original i
string
2
That last "2" being res.rows[0].id.
I really believe this must have something to do with the blasted "promises" and asyncronous stuff. But my previous "solution" won't fit here. I can't just do everything inside of that block where I have access to res. I have to be able to return some data back to getPaymentInfo().
It seems that client.query(...) is waiting for every line in getPaymentInfo() to be ran before actually doing anything. I can see that because in the console, the results of console.log(result) and console.log(typeof result) appear before the line that shows information from the table (from console.log(err ? err.stack : res.rows[0].id) ). That is absolutely infuriating.
I called the pg.select() function. That function calls client.query(). client.query should do its thing, return to select(), which would then return to getPaymentInfo() and then keep going and do what the next lines say. That's normal behaviour for any program. Clearly that's not happening here.
I saw some examples out there that used await, but when I tried to add that copying the examples, it gave me a syntax error as if it didn't recognize what await is supposed to be. There was an example with yield as well, same error. It doesn't know what those commands mean. I'm using the latest version of nodejs (v8.10.0).
I also tried using then to get it to wait:
function generatePaymentInfo(params){
...
pg.select().then(function(v) {
console.log(v);
});
...
}
It gives me this error:
TypeError: Cannot read property 'then' of undefined
What's going on here? How do I get it to do things in the right order? All I want is to get some information from a table. Every example for the pg package (and pg-promise as well) I see out there just has a console.log() representing "success". In reality what anyone would want is to have actual access to the data.
i have a csv that I want to save into my mySQL Table. My parser works well and it also save the created json Array to my table. My problem is that he insert row for row in the background and don't response it.
My code looks like that:
var file= './mytable.csv';
connection.connect(function (err) {});
var csv = require('csvtojson');
csv({ delimiter:","})
.fromFile(file)
.on('end_parsed', function(jsonArray){
for(var i = 0; i < jsonArray.length; i++){
var post = jsonArray[i]
conn.query('INSERT INTO mytable SET ?', post, function(err, results) {
if (err) throw err;
console.log(result.insertId);
});
}
res.end("done");
})
.on('done', function(error){
console.log('end')
})
My Goal is that my api send: its "done" with (res.json("Done")) when the complete query is done. What should I change?
Greetings
edit: my csv is realy large, with almost 500k rows!
EDIT:
I inserted async into my parser like that:
csv({ delimiter:";"})
.fromFile(file)
.on('end_parsed', function(jsonArray) {
async.forEach(jsonArray, function (jsonArrays, callback) {
conn.query('INSERT INTO mytable SET ?', jsonArrays, callback);
}, function (err) {
if (err) return next(err);
res.json("done");
console.log("done")
});
});
But he don't responde with "done" (in Terminal he write it, but postman give me only "Could not get any response")
Your call to res.end()/ res.json() doesn't wait for all inserts to be finished.
And if you start your inserts within a for-loop you start them all more or less in parallel. You should take look at something like the async library (http://caolan.github.io/async). There you find a eachLimit() function that lets you run async operations on a collection/array. With this function you can limit how many operations can run in parallel. And you get a callback that is called when an error happens or all async calls have finished. Within this callback you can call the res.json(...) function to send your response.
Sample:
var async = require('async');
//...
function save_row_to_db (post, callback) {
conn.query('INSERT INTO mytable SET ?', post, callback);
}
function finished(err) {
if (err) throw err;
res.end("done");
}
async.eachLimit(csvRows, 20, save_row_to_db, finished);
This has to be a scope issue that I'm not familiar with. I have a small module I've written as so:
(function () {
var getPlanInfo = function (id, conn) {
conn.query('SELECT * FROM `items` WHERE `id` = ?', [id], function (error, result) {
if (error) console.error('Query error: ' + error.stack);
console.log(result[0]); // Everything is great
return result[0];
});
};
modules.exports.getPlanInfo = function (id, conn) { return getPlanInfo(id, conn); // Typo }
})();
Here comes the problem. When I call it from anywhere (inside the module itself or another file), the return value is always undefined. I checked from within the function, the query returns the result as expected.
var backend = require('./module.js');
var t = backend.getPlanInfo();
t is undefined. This is the same if I call that method from inside the module itself (another function within that module).
I'm familiar with the callback principle in javascript and how objects and functions have to be passed around as an argument to remain in scope. Is this the issue here or is this a node.js particularity?
I tried in in the Developer Console (Chrome), works as expected.
conn.query() looks like it is async. Thus, you can't return its result from getPlanInfo() because getPlanInfo() returns long before the result is available. Returning result[0] from the conn.query() callback just returns a piece of data back into the conn.query() infrastructure. getPlanInfo() has long before already returned.
If you want an async result, then you will have to change getPlanInfo() to use a mechanism that supports getting async results such as a direct callback or a promise or something like that.
Here's a plain callback way:
var getPlanInfo = function (id, conn, callback) {
conn.query('SELECT * FROM `items` WHERE `id` = ?', [id], function (error, result) {
if (error) {
console.error('Query error: ' + error.stack);
callback(error);
return;
}
console.log(result[0]); // Everything is great
callback(0, result[0]);
});
};
modules.exports.getPlanInfo = getPlanInfo;
Then, the caller of that module would look like this:
var m = require('whatever');
m.getPlanInfo(id, conn, function(err, result) {
if (err) {
// error here
} else {
// process result here
}
});
You don't return anything from getPlanInfo. Probably you wanted to write modules.exports.getPlanInfo = function (id, conn) { return getPlanInfo; }
(with return getPlanInfo; instead of return getPlanInfo();)
I got a file newuser.js (node.js environment featuring a mongodb database managed via mongoose) containing the following code:
//newuser.js
//basically creates new user documents in the database and takes a GET parameter and an externally generated random code (see randomcode.js)
[...]
var randomCode = require ('randomcode');
var newTempUser = new tempUser({name: req.body.name, vericode: randomCode.randomveriCode(parameter)
});
newTempUser.save(function (err){
//some output
});
//randomcode.js
//creates a random sequence of characters (=vericode), checks if code already exists in DB and restarts function if so or returns generated code
exports.randomveriCode = function randomveriCode(parameter){
[...]
var TempUser = conn.model('TempUser', TempUserSchema);
TempUser.count({vericode: generatedcode}, function(err, counter){
if (counter=='0'){
return generatedcode;
}else{
randomveriCode(parameter);
}
});
};
Problem is, that newuser.js throws an error as variable vericode is 'undefined' (thus mongoose model validations fails). The error does not occur if I skip the database query and instantly return the generated code (which in fact has got a value as verified by several console.log instructions). It occurs to me that the db query takes to long and empty or null value returned before query is complete? I thought about introducing promises unless you got any other suggestions or hints what may cause this behaviour?
Kind regards
Igor
Since querying the database is a non-blocking operation, you cannot expect the function call to return the value from the database immediately. Try passing in a callback instead:
// newuser.js
var randomCode = require('randomcode');
randomCode.randomveriCode(parameter, function(err, code) {
if (err) throw err; // TODO: handle better
var newTempUser = new tempUser({name: req.body.name, vericode: code});
newTempUser.save(function (err){
//some output
});
});
// randomcode.js
exports.randomveriCode = function randomveriCode(parameter, cb) {
var TempUser = conn.model('TempUser', TempUserSchema);
TempUser.count({vericode: generatedcode}, function(err, counter) {
if (err) return cb(err);
if (counter == '0') {
cb(null, generatedcode);
} else {
randomveriCode(parameter, cb);
}
});
};
your randomveriCode function contains calls to an asynchronous function and therefore, your function really needs to provide a callback argument like this:
exports.randomveriCode = function randomveriCode(parameter, callback){
[...]
var TempUser = conn.model('TempUser', TempUserSchema);
TempUser.count({vericode: generatedcode}, function(err, counter){
if(err) return callback(err);
if (counter=='0'){
return callback(null, generatedcode);
}else{
randomveriCode(parameter, callback);
}
});
};
You'd then call it like so:
var randomCode = require ('randomcode');
randomCode(function(err, vericode){
if(err) throw err;
var newTempUser = new tempUser({name: req.body.name, vericode: vericode});
newTempUser.save(function(err,newUser){
//do something here
});
});
Btw - you could also use a synchronous function to create a GUID. See https://www.npmjs.org/package/node-uuid.