What i'am trying to achieve is to make DB query inside closure. Return data and then send stuff to user. I understand that best practice is to use database pooling. Problem is that query is not sync.
Simplified code:
server.js
var express = require('express'),
app = express(),
server = require('http').createServer(app),
mysql = require('mysql');
app.set('DB:pool', mysql.createPool(process.env.DATABASE_URL));
var myClosure = require('./closure.js')(app));
app.get('/somepage', function(req, res) {
var data = myClosure.myquery();
res.send(data);
});
app.get('/anotherpage', function(req, res) {
var data = myClosure.myquery();
res.send(data);
});
app.listen(3000);
closure.js
function myClosure(app) {
var pool = app.get('DB:pool');
return {
myquery: function(inp) {
pool.getConnection(function(err, db) {
if (err) throw err;
db.query('SELECT * FROM table', function(err, rows, fields) {
if (err) throw err;
data = rows[0]
db.release();
});
});
return data;
}
};
}
module.exports = myClosure;
In examples i found all DB related stuff were made in route callback and response was sent in query callback. But way i'm trying to do it is not working as myquery returns undefined because sql query is not done there.
So what is correct way to handle querys ?
Make your query-function handle a callback too:
// server.js
app.get('/somepage', function(req, res) {
myClosure.myquery(function(err, data) {
// TODO: handle error...
res.send(data);
});
});
// closure.js
...
myquery: function(callback) {
pool.getConnection(function(err, db) {
if (err) return callback(err);
db.query('SELECT * FROM table', function(err, rows, fields) {
// release connection before we return anything, otherwise it
// won't be put back into the pool...
db.release();
if (err) return callback(err);
callback(null, rows[0]);
});
});
}
(I left out the inp argument because that didn't seem to be used)
Related
I just started learning node.js...
Here is an example of my code. In this example everything works.
But, I have a question. How to make several SQL queries and send results to template?
At the moment I can only do this for one query...
Thanks.
//connection database
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'password',
database : 'test'
});
connection.connect(function (err){
if (err) throw err;
console.log('Database connected . . . \n\n');
});
router.get('/', function(req, res, next) {
var sql = 'SELECT * FROM `test`';
connection.query(sql, function(err, rows, field){
if (err) throw err;
res.render('index', {
data: rows
})
});
});
Here is an answer following my comment since you mentioned you couldn't figure it out on your own.
First snippet uses promises, a quick helper function, but no external library. Second snippet uses the external async.js library and is a bit more callback-heavy. Both of them tackle the problem assuming we want the queries to be executed in parallel.
With promises
router.get('/', async function(req, res, next) {
var queries = ['SELECT * FROM `test`',
'SELECT * FROM `test2`',
'SELECT * FROM `test3`'];
var allResults = [];
/*transform our `query` array into an array of promises, then
await the parallel resolution of all the promises*/
var allQueryRows = await Promise.all(queries.map(query => promiseQuery(query)));
/*'allQueryRows' is an array of rows, so we push each of those
into our results*/
allQueryRows.forEach(function(rows){
allResults.push(...rows);
});
res.render('index', {
data: allResults
})
});
function promiseQuery(sqlQuery){
return new Promise((resolve, reject) => {
connection.query(sqlQuery, function(err, rows, field){
if(err)
return reject(err);
resolve(rows);
})
})
}
With callbacks and async.js
const async = require('async');
router.get('/', function(req, res, next) {
var queries = ['SELECT * FROM `test`',
'SELECT * FROM `test2`',
'SELECT * FROM `test3`'];
var allResults = [];
async.each(queries, function(sqlQuery, callback){
connection.query(sqlQuery, function(err, rows, field){
if(err)
throw err;
allResults.push(...rows);
callback();
});
}, function(){
res.render('index', {
data: allResults
});
});
});
I tried to get result using mysql database query from called function but do not wait for result in called function. Following is my code for users.js file. I got result in getBankDetail function but do not get result in users function.
var db = require("../db/mysqlconnection");
function users(app){
app.get("/users",async function(req, res, next){
let bankDetail = await getBankDetail();
console.log("bankDetail",bankDetail); //Here I do not got result
return res.send(bankDetail);
});
}
async function getBankDetail(){
db.getConnection(async function(err, connection) {
if (err) throw err; // not connected!
await connection.query('SELECT * FROM bank', function (error, results, fields) {
connection.release();
if (error) throw error;
console.log("bank result",results); //Here I got result
return results;
});
});
}
module.exports = users;
My Question is why do not wait for result in called function? I also used async/await functionality.
function getBankDetail(){
return new Promise((resolve, reject) => {
db.getConnection(function(err, connection) {
if (err) reject(err); // not connected!
connection.query('SELECT * FROM bank', function (error, results, fields) {
connection.release();
if (error) reject(err);
console.log("bank result",results); //Here I got result
resolve(results);
});
});
});
}
And then you can use let bankDetail = await getBankDetail();
If you want to use await on your db.getConnection and connection.query you will have to use mysql2/promises library or promisify those functions yourself
Here is the implementation when you use the promisified version of your database driver:
async function getBankDetail(){
const connection = await db.getConnection();
const data = await connection.query('SELECT * FROM bank');
connection.release();
console.log("bank result", data[0]); //Here I got result
return data[0];
}
I'm using ExpressJS importing MySQLJS. With ExpressJS as back-end, I have a service called /get-candidates where ExpressJS tries to fetch a couple of data from MySQL table and is returned to requester. I'm looking for a way to properly close MySQL DB Connection before returning the JSON to requester.
Here's what my /get-candidates looks like:
module.exports.getCandidates = function (request, response) {
var mysql = require("mysql");
var connectionSettings = require("../db.conf.json");
var connection = mysql.createConnection(connectionSettings);
connection.connect();
connection.query('SELECT * FROM Candidates', function (err, rows, fields) {
if (err) {
throw err;
} else {
response.json(rows);
}
});
connection.end(); // I don't think the code reaches this part after line 'response.json(rows)'
};
You can close connection once you get the query results either it is error or successfully fetched records.
module.exports.getCandidates = function(request, response) {
var mysql = require("mysql");
var connectionSettings = require("../db.conf.json");
var connection = mysql.createConnection(connectionSettings);
connection.connect();
connection.query('SELECT * FROM Candidates', function(err, rows, fields) {
connection.end();
if (err) {
throw err;
} else {
response.json(rows);
}
});
};
I don't see why you want to achieve this, but all you have to do is make a variable and send it a response after connection.
module.exports.getCandidates = function (request, response) {
var mysql = require("mysql");
var connectionSettings = require("../db.conf.json");
var connection = mysql.createConnection(connectionSettings);
var myRows; // our variable
connection.connect();
connection.query('SELECT * FROM Candidates', function (err, rows, fields) {
if (err) {
throw err;
} else {
myRows = rows;
//response.json(rows);
}
});
connection.end();
console.log(myRows); // To check if we have the value
response.json(myRows);
};
I've been using mountebank to do some stubbing for performance testing and its an awesome tool. The functional teams have asked if it can be repurposed to support functional testing and I'd said i'd have a look.
What I want to achieve is to select from a mysql database an account number and its account balance and then return the balance to the client (in this case a jmeter harness)
function (request, state, logger) {
logger.info('GBG - getAccountBalance');
var mysql = require('mysql');
var result = '';
var con = mysql.createConnection({
host: "localhost",
user: "user",
password: "password",
database: "customer"
});
con.connect(function(err) {
if (err) throw err;
console.log("Connected!");
});
con.query('select * from accounts', function (err, rows, fields) {
if (err) throw err;
console.log(rows);
console.log('accountNumber is : ', rows[0].accountNumber);
result = rows[0].accountNumber;
});
console.log('result is : ', result);
var response = result;
return {
headers: {
'Content-Type': 'application/xml',
'Connection': 'Keep-Alive'
},
body: response
};
}
The result of the console log is:
result is :
Connected!
[ RowDataPacket { accountNumber: 777777, accountBalance: 777 } ]
accountNumber is : 777777
Not sure what I'm doing wrong and why the result is : lines comes up first despite being later in the code.
Any advice appreciated.
Full disclosure, I've been using mountebank for about two weeks so I'm a real beginner.
The function keyword inside connect and query is called callbacks, and only executed after the function itself is done. so your code would look like:
con.connect(function(err) {
if (err) throw err;
console.log("Connected!");
con.query('select * from accounts', function (err, rows, fields) {
if (err) throw err;
console.log(rows);
console.log('accountNumber is : ', rows[0].accountNumber);
result = rows[0].accountNumber;
console.log('result is : ', result);
var response = result;
});
});
and so on, but you just introduced callback hell to your code.
async is your friend.
EDIT:
following an example:
async.waterfall([
function (callback) {
//do some async function here
con.connect(function(err) {
if (err) throw err;
console.log("Connected!");
//call this when you are done
//you can even pass param to next function
callback(null,true);
});
},function (isConnected,callback1) {
if !(isConnected){
console.log("Connection failed! Skipping Query...")
callback1(null,"Error");
}
//do another async function here:
con.query('select * from accounts', function (err, rows, fields) {
if (err) throw err;
console.log(rows);
console.log('accountNumber is : ', rows[0].accountNumber);
result = rows[0].accountNumber;
callback1(null,"Complete");
});
}
], function (err,result) {
if(result == "Error"){
alert("Someting went wrong!");
}
if(result == "Complete"){
alert("Done!");
}
return 0;
});
note:I haven't written JS for awhile. Written this off of some existing code and haven't been tested. Also, Promise is also something that would help, but haven't looked into personally. BlueBird is a library for that.
The simplest way to get Data form mysql database using Promise and async await.
Get data dynamically by providing id to the SQL query.
With the help of following code snippet. First Your query will get execute fully the other process will execute.
response will be sent after execution of query is fully done. (sometimes response is sent first then execution of query completes)
async function getData(customerId){
let sql = `SELECT * FROM customer_info WHERE customerID = ${customerId}`
await connection.query(sql, (err, result) => {
data = {
CustomerId : result[0].customerID,
FirstName: result[0].FirstName,
LastName: result[0].LastName
}
})
}
function connectToDB(customerId){
return new Promise((resolve, reject) => {
getData(customerId).then(()=>resolve())
})
}
app.get('/customer/:id', (req, res) => {
let customerId = req.params.id
// Caller Function to all functions
async function callerFun(){
await connectToDB(customerId);
res.send("Execution Done");
}
callerFun();
})
I have this code:
server.js:
var sql = require('./libs/mysql');
app.get('/status', function(req, res) {
res.send(sql.readName('1600'));
});
mysql.js:
exports.readName = function(name){
var connection = mysql.createConnection(option);
connection.connect();
connection.query('SELECT id FROM asterisk.users WHERE name= '+name, function (err, rows, fields) {
console.log('mysql: ' +rows[0].id);
return(rows[0].id);
});
Now, when I send GET http://mydomain.com/status I can not receive responce. But in console log I see correct answer. Where is my error?
Most disk reading/DB access in node.js is done asynchronously. This allows node.js to be as fast as it claims. You need to use callback functions to handle the result of these read operations. If you are familiar with ajax, the concept is similar.
You are returning from connection.query which runs asynchronously. This is returned nowhere. readName actually returns nothing. What you need to do is actually pass in the callback that returns the value:
app.get("/status", function (req, res) {
sql.readName("1600", function (err, rows, fields) {
/* handle err */
res.send(rows[0].id);
});
});
This callback has to be called of course:
exports.readName = function (name, cb) {
/* snip */
connection.query(query + name, cb);
});
You can't get the result because the return statement is in the function function (err, rows, fields). You can use callback like this
var sql = require('./libs/mysql');
app.get('/status', function(req, res) {
sql.readName('1600', function(result){
res.send(result);
});
});
exports.readName = function(name, callback){
var connection = mysql.createConnection(option);
connection.connect();
connection.query('SELECT id FROM asterisk.users WHERE name= '+name,
function (err, rows, fields) {
console.log('mysql: ' +rows[0].id);
callback(rows[0].id);
});
}
Thanks for helping. I find http error causes described upper. Error appear if I use callback functions like this callback(row[0].id), but if we use syntax like this callback('id: '+row[0].id) everything it's ok. So when we send res.send(response) we cant send unnamed data, need to put there some descriptions.
So, my final code look like this:
server.js
var sql = require(./mysql);
app.get('/status', function(req, res) {
sql.readName('1600', function(result){
res.send(result);
});
});
mysql.js
var mysql=require(mysql);
exports.readName = function(name, callback){
var connection = mysql.createConnection(option);
connection.connect();
connection.query('SELECT id FROM asterisk.users WHERE name= '+name,
function (err, rows, fields) {
if(err) callback(err);
else{
console.log(rows[0].id);
callback('ID: '+rows[0].id);
}
});
return true;
};