express.js with MySQL - mysql

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
});
});
});

Related

Express and mysql. rows are undefined

This is my code. I am writing API and I want to send information about products that client has input.
const express = require('express');
const mysql = require('mysql');
const morgan = require('morgan');
const app = express();
app.use(morgan('short'));
app.use(express.static('./public'));
// app.get('/', (req, res, next)=>{
// res.send('Hello World');
// });
function getConnection(){
return mysql.createConnection({
host: 'localhost',
user: 'root',
password:'samsung793',
database: 'demo2'
})
}
app.get('/models/:id', (req, res, next)=>{
console.log('Fetching id ' + req.params.id);
const connection = getConnection();
const queryStr = 'SELECT * FROM products WHERE id=?'
const modelId = req.params.id;
connection.query( queryStr, [modelId], (err, rows, fields)=>{
if (err){
res.send('<h1>500 bad request</h1> Error! Sorry for error, we are working on it!');
res.sendStatus(500);
return;
//throw err;
}
console.log('Ready');
res.json(rows);
})
// res.end();
})
app.get('/:name', (req, res, next)=>{
console.log('Fetching name ' + req.params.name);
const connection = getConnection();
const queryStr = `SELECT * FROM products WHERE MATCH(name) AGAINST(${req.params.name}, in natural language)`
const modelName = req.params.name;
connection.query( queryStr, [modelName], (err, rows, fields)=>{
if (err){
res.send('<h1>500 bad request</h1> <h3>Error!</h3> <h4>Sorry for error, we are working on it!</h4>');
res.sendStatus(500);
return;
//throw err;
}
console.log('Ready');
res.json(rows);
console.log(rows);
})
// res.end();
})
app.listen(3000, ()=>{
console.log('server is listening on port 3000');
} )
when I log to console the rows, it is undefined. How can I fix it? What is the problem?
Sorry for first post. I edit and add all code now. Please help me to solve this problem.
You need to check if any error occur while querying
app.get('/:name', (req, res, next) => {
console.log('Fetching name ' + req.params.name);
const connection = getConnection();
const queryStr = 'SELECT * FROM products WHERE MATCH(name) AGAINST(?, in natural language mode)';
const modelName = req.params.name;
connection.query( queryStr, [modelName], (err, rows, fields)=>{
console.log('Ready');
if(err) {
console.log(err);
return res.status(500).send(err);
}
console.log(rows);
res.json(rows);
})
})
If you are using prepared statement, you do not need to pass ${req.params.name}, just pass ?
Thank you for answers. I write code here in case someone needs it.
It works this way:
app.get('/:name', (req, res, next)=>{
console.log('Fetching name ' + req.params.name);
const connection = getConnection();
const queryStr = `SELECT * FROM products WHERE MATCH(name, url) AGAINST(? IN NATURAL LANGUAGE MODE) `
const modelName = req.params.name;
connection.query( queryStr, modelName, (err, rows, fields)=>{
console.log(rows);
if (err){
res.status(404).send(" Something went wrong");
// res.sendStatus(500);
throw err;
}
console.log('Ready');
res.json(rows);
})
// res.end();
})

NodeJS Output user in browser

I made a project where i include database which i wrote on mysql and it make a json file from database and also output all users in browser but I have some problem. I want to output one user how can i do this(this is example how it must output http://localhost:8080/user/1). I used express and mysql. Please help me. Thanks.
This is my code:
'use strict';
const mysql = require('mysql');
const express = require('express');
const http = require('http');
const router = express()
// http://nodejs.org/docs/v0.6.5/api/fs.html#fs.writeFile
const fs = require('fs');
const connection = mysql.createConnection({
host: 'localhost',
user: 'lado',
password: '1234'
});
connection.connect();
connection.query('SELECT * FROM bankdb.account;', function(err, results, fields) {
if(err) throw err;
fs.writeFile('account.json', JSON.stringify(results), function (err) {
if (err) throw err;
console.log('Saved!');
});
connection.end();
});
const pool = mysql.createPool({
host: 'localhost',
user: 'lado',
password: '1234',
database: 'bankdb',
charset: 'utf8'
});
var reo ='<html><head><title>Output From MYSQL</title></head><body><h1>Output From MYSQL</h1>{${table}}</body></html>';
function setResHtml(sql, cb){
pool.getConnection((err, con)=>{
if(err) throw err;
con.query(sql, (err, res, cols)=>{
if(err) throw err;
var table =''; //to store html table
//create html table with data from res.
for(var i=0; i<res.length; i++){
table +='<tr><td>' + (i+1) +'</td><td>'+ res[i].name +'</td><td>'+ res[i].address +'</td></tr>';
}
table ='<table border="1"><tr><th>ID</th><th>Name</th><th>Amount</th></tr>'+ table +'</table>';
con.release(); //Done with mysql connection
return cb(table);
});
});
}
const sqll ='SELECT * FROM bankdb.account';
const server = http.createServer((req, res)=>{
setResHtml(sqll, resql=>{
reo = reo.replace('{${table}}', resql);
res.writeHead(200, {'Content-Type':'text/html; charset=utf-8'});
res.write(reo, 'utf-8');
res.end();
});
});
server.listen(8080, ()=>{
console.log('Server running at //localhost:8080/');
router.get('/users/:id', function(req, res, next) {
var user = users.getUserById(req.params.id);
res.json(user);
});
exports.getUserById = function(id) {
for (var i = 0; i < users.length; i++) {
if (users[i].id == id) return users[i];
}
};
});
Just get the specific user based on their id:
router.get( '/user/:id', function( req, res ) { // When visiting '/user/:id'
var id = req.params.id; // For example if you visit localhost/user/24 the id will be 24
connection.query('SELECT * FROM bankdb.account WHERE id=' + mysql.escape( id ), function(err, results, fields) {
if(err) throw err;
fs.writeFile('account.json', JSON.stringify(results), function (err) {
if (err) throw err;
console.log('Saved!');
});
connection.end();
});
} );
If you grab every user from the database, your program will use up much more memory.
Just grab the one you need and work with him.

node.js mysql result into a variable

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();
})

How to merge various MySQL queries results in a single JSON object

I'm trying to write a REST API set in NodeJS to retrieve data from my MySQL database.
Here the code:
var express = require('express');
var mysql = require('mysql');
var app = express();
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'root',
database : 'apitest',
port : '3306',
multipleStatements: true
});
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.get('/users', function(req, res) {
connection.query('SELECT name, surname, address FROM users', function(err, results) {
if (err) throw err;
if (results) {
res.status(200).send(results);
};
});
});
app.get('/users/:userId', function (req, res) {
var userId = req.params.userId;
connection.query('SELECT * FROM users WHERE idUser = ?', [userId], function(err, result) {
if (err) throw err;
if (result) {
res.status(200).send(result);
};
});
});
app.get('/users/:userId/photos', function (req, res) {
var userId = req.params.userId;
connection.query('SELECT date, file, tags FROM photos WHERE idUser = ?', [userId], function(err, results) {
if (err) throw err;
if (results) {
res.status(200).send(JSON.stringify(results));
}
});
});
var server = app.listen(8080, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Listening on http://%s:%s', host, port);
});
Everything goes well if I use the single REST call as written above.
The problem is that I want it to work differently, so when i call /users/:userId i want to retrieve user data and the relative photos in a single, well structured, JSON response.
Eg:
{
"name" : "John",
"surname" : "Doe",
"photos" : [
{
"date" : "2015-04-19T22:00:00.000Z",
"file" : "photo1.jpg",
"tags" : "holidays, 2015"
},
{
"date" : "2015-04-19T22:00:00.000Z",
"file" : "photo2.jpg",
"tags" : "holidays, 2015, nassau"
}
]
}
I've find a workaround by modifying the /users/:userId call as mentioned above:
app.get('/users/:userId', function (req, res) {
var userId = req.params.userId;
connection.query('SELECT * FROM users WHERE idUser = ?', [userId], function(err, results1) {
if (err) throw err;
if (results1) {
connection.query('SELECT date, file, tags FROM photos WHERE idUser = ?', [userId], function(err, results2) {
if (err) throw err;
if (results2) {
results1[0].photos = results2;
res.status(200).end(JSON.stringify(results1[0]));
}
});
}
});
});
Everything seems to go well but I think is not the right way because if i want to add more information from other tables in my object i would have to nest more and more functions...
Any suggestion?
Thanks in advance.
Check out Async, or any one of the popular promise libaries(when.js, Q.js, Bluebird).
In Async, it might look something like this.
var async = require('async');
app.get('/users/:userId', function (req, res) {
var userId = req.params.userId;
async.parallel({
user: function(callback){
connection.query('SELECT * FROM users WHERE idUser = ?', [userId], callback)
},
photos: function(callback){
connection.query('SELECT date, file, tags FROM photos WHERE idUser = ?', [userId], callback)
}
},
// Final callback, with all the results
function(err, results){
//results now has {user: ..., photos: ...}
var user = results.user;
user.photos = results.photos;
res.status(200).end(JSON.stringify(user));
});
});
Adding another call is as simple as adding another function inside parallel (or whatever it may be). The code is pretty similar for the promise libraries so I'll leave that as an exercise to you!
Let me know that this helped.

Node.js, Express and Mysql. How is correct way

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)