how to pass mysql result to variable to render in template engines - javascript

I want to store mysql result to a variable, so i can pass to the template engine. I have multiple mysql queries and need to save every query result to different variables.
I am using Node JS and express JS
Below is my code (app.js)
var mysql = require('mysql');
var db = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '',
database : 'my_db'
});
db.connect(function(err) {
if (err) throw err;
console.log('Database connected');
});
app.get('/', (req, res) => {
var emp_result;
var task_list_result;
db.query('SELECT * FROM emp', function (error, results, fields) {
if (error) throw error;
emp_result = results;
});
db.query('SELECT * FROM task_list', function (error, results, fields) {
if (error) throw error;
task_list_result;
});
res.render('dashboard',{"emp_res" : emp_result, "task_res" : task_list_result});
});
I am expecting that result should be store in a variable;

Using async await here to handle the asynchronous network calls. I f you want to use callback function, you should chain it one inside the other.
const {promisify} = require('util');
app.get('/', async (req, res) => {
const query = promisify(db.query).bind(db);
const emp_result = await db.query('SELECT * FROM emp')
const task_list_result = await db.query('SELECT * FROM task_list')
res.render('dashboard',{"emp_res" : emp_result, "task_res" : task_list_result});
});
Using Promise.all to make calls in parallel, as they are not dependent on each other, it increases the performance, you can use the below code-
const {promisify} = require('util');
app.get('/', async (req, res) => {
const query = promisify(db.query).bind(db);
const [emp_result, task_list_result] = await Promise.all([db.query('SELECT * FROM emp'), db.query('SELECT * FROM task_list')]);
res.render('dashboard',{"emp_res" : emp_result, "task_res" : task_list_result});
});
Using callback function, as you were using -
app.get('/', (req, res) => {
db.query('SELECT * FROM emp', function (error, results, fields) {
if (error) throw error;
const emp_result = results;
db.query('SELECT * FROM task_list', function (error, results, fields) {
if (error) throw error;
const task_list_result = results;
res.render('dashboard',{"emp_res" : emp_result, "task_res" : task_list_result});
});
});
});
You can use any of these, but second one is the best approach to follow.

Related

Executing mysql query suspends process and code after won't be executed

I'm asking help as I'm trying to get 2 different sets of data from a mysql db. I've written 2 separate functions using promisify. Unfortunately when I execute this node file only the first function gets executed and shown in the console. After some debugging I think it's await query(...) the cause of this problem. After this query (the one inside getSources() ) is executed, the process is suspended and I've got to terminate it. I also tried using mysql2 and moving con.end() to a different line unsuccesfully. Of course any help we'll be appreciated.
import mysql from 'mysql';
import { promisify } from 'util';
import express from 'express';
import path from 'path';
const sql = "SELECT `id` FROM `probes` WHERE `country`= ?";
const sql1 = "SELECT `fqdn` FROM `anchors` WHERE `country`= ?";
let sources = []; //sources
let targets = []; //targets
const app = express();
const __dirname = path.resolve();
app.use(express.urlencoded( {extended: true} ));
app.use(express.static(__dirname));
const con = mysql.createConnection({
host:'localhost',
user:'root',
password:'',
database:'probes&anchors'
});
const query = promisify(con.query).bind(con);
const getSources = async (from) => {
console.log("I'm in getSources");
con.connect((err)=>{
if(err){
console.log("Connection not proper");
}else{
console.log("connected");
}
});
await query(sql, [from], (err, rows) => {
console.log("error in query: "+ err);
if (err) throw err;
rows.forEach((v) => {
sources.push(v.id);
});
console.log(sources);
con.end(err => {
if(err) console.log(`${err.toString()}`)
console.log('con ended')
});
});
};
const getTargets = async (to) => {
console.log("I'm in getTargets");
con.connect((err)=>{
if(err){
console.log("Connection not proper");
}else{
console.log("connected");
}
});
await query(sql1, [to], (err, rows) => {
console.log(err);
if (err) throw err;
rows.forEach((v) => {
targets.push(v.fqdn);
});
con.end(err => {
if(err) console.log(`${err.toString()}`)
console.log('con ended')
});
});
};
app.post('/', async function(req,res){
await getSources(req.body.from_country);
await getTargets(req.body.to_country);
console.log(sources);
console.log(targets);
res.send("Loaded");
});
app.get('/', (req, res) => res.send('Hello World! From Node.js'));
app.listen(8000, () => console.log('Example app listening on port 8000!'));

How to use .then method for promises with mySQL?

I know that mongodb has their own way of handling native promises with no rejection issues but I guess it doesnt work the same here with mysql. Is there anyway I can use .then in mysql? I was able to do it using more callbacks but I would like to use promises to make the solution cleaner or even use async/await if that makes it simpler too. I need to use a callback to jump to my server file, I have all my methods defined in my db file.
Server file:
app.get('/api/cows', (req, res) => {
db.reqMethods.getAll((err, data) => {
if (err) {
res.send('Error');
} else {
res.send(data);
}
});
});
db file:
const mysql = require('mysql');
const http = require('http');
const express = require('express');
const path = require('path');
const bodyParser = require("body-parser");
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'cowlist'
});
connection.connect((err) => {
if (err) {
console.log(err);
} else {
console.log('Connected to MySQL!')
}
});
// Your Database Queries Here!!
module.exports.reqMethods = {
// GET All Cow Info
getAll: function (callback) {
const query = connection.query('SELECT * FROM cows;');
query.then(data => callback(null, data));
});
};
// callback solution that I'd like to simplify:
// getAll: function (callback) {
// connection.query('SELECT * FROM cows;', (err, data) => {
// if (err) {
// callback(err, null);
// } else {
// console.log("DATA: \n", data);
// callback(null, data);
// }
// });
// }
Yes, this is possible by using mysql2 npm package.
So in your database.js file, use this method.
const mysql = require('mysql2');
var pool_connection = mysql.createPool({
host: '127.0.0.1',
port: 3306,
user: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
connectionLimit: 10,
multipleStatements: true
});
pool_connection.getConnection((err) => {
if (err) console.log(JSON.stringify(err));
else {
console.log('Connected!')
}
});
module.exports = pool_connection.promise();
And in your models, you require the connection as follows and make use of async-await in a try-catch block.
const con = require('/path/to/your/database_file');
module.exports = class Messages {
constructor() { }
static async getMessage(arguments_here) {
const query = "some query here with params if required. Use ? for placing params and do not use string literal to embed params.";
try {
const [response] = await con.execute(query, [params]);
return response;
} catch (error) {
console.log(error);
return null;
}
}
}
And in your controller,
const Messages = require('../models/Messages');
const someFn = async (req, res) =>{
try {
const result = await Messages.getMessages('sample_arguments');
//do something with result
}
catch(err){
console.log(err);
}
}

RESTful API access token mechanism

I'm developing a JavaScript/MySQL RESTful API for a business manager system using Express, Body-parser and MySQL. Currently, I am working on access tokens. Before any API call, the body must include an API key that is being verified by the API. In every API call function, I first check if the access token exists and if so, the API executes MySQL commands and sends back results.
The important thing is that I want to create a function that checks whether the access token exists and returns true or false. However, I can't figure out how to return this boolean value from the conn.query() method. Any help will be very much appreciated, I am desperate.
Here is my code:
function checkApiKey(apiKey) {
let sql = "SELECT * FROM apikeys WHERE apikey = '" + apiKey + "'";
conn.query(sql, (err, results) => {
if (err) throw err;
if (results.length > 0) return true;
return false;
});
}
app.get("/api/users",(req, res) => {
if (checkApiKey(req.body.apiKey)) {
let sql = "SELECT * FROM users";
let query = conn.query(sql, (err, results) => {
if (err) throw err;
res.send(results);
});
}
});
However, the checkApiKey() method returns undefined...
Your checkApiKey function returns undefined, because your logic returns true or false within sql's callback function.
I'd recommend another approach, using checkApiKey as middleware function:
const checkApiKey = (req, res, next) => {
conn.query("SELECT * FROM apikeys WHERE apikey = ?", [req.body.apiKey], (err, result) => {
if (err) throw err
if (results)
next() // continue to next router function
else
res.status(403).end('Unauthorized') // resolve with 403
})
}
app.get("/api/users",
checkApiKey, // middleware auth function
(req, res) => {
conn.query("SELECT * FROM users", (err, results) => {
if (err) throw err;
res.send(results)
})
})

Node JS MongoDB collection.find.toArray returns no value

I'm building a website that lets people write sticky notes and print it to them on the screen. I want to store the sticky notes inside a mongoDB with a db called stickyNotes and a collection called stickyNotes which currently has two documents.
I have a variable called stickyNotes which suppose to get the documents from the stickyNotes collection on the db but when I use the collection.find.toArray from the mongodb library to enter the documents to the stickyNotes variable in an asynchronous way, it shows an empty array value.
This is my server.js file:
const express = require("express");
const mongo = require("mongodb").MongoClient;
const app = express();
let stickyNotes = [];
//mongodb get all sticky notes
const mongoUrl = "mongodb://localhost:27017";
mongo.connect(mongoUrl, { useNewUrlParser: true }, async function(
err,
connection
) {
if (err) {
console.error(err);
} else {
console.log("Succesfully connected to the database");
const db = connection.db("stickyNotes");
const stickyNotesCollection = db.collection("stickyNotes");
stickyNotes = await stickyNotesCollection.find({}).toArray();
}
connection.close();
});
console.log(stickyNotes);
app.use(express.static("./src/public"));
app.get("/sticky-notes", (req, res) => {
console.log("Got a request for sticky notes");
res.json(stickyNotes);
});
const port = 3000;
app.listen(port, () => {
console.log(`App is running on port ${port}`);
});
Can try with:
stickyNotesCollection.find({}, (err, result) => {
if (err) throw err;
stickyNotes = result;
});
or find result in array:
collection.find().toArray(function(err, result) {
console.log(result);
});
or iterate:
collection.find().each(function(err, result) {
//once result
});

What is wrong with my database file?

this is my database.js file:
const MongoClient = require('mongodb').MongoClient;
const db = function(){
return MongoClient.connect('mongodb://localhost:27017/users', (err, database) => {
if (err) return console.log(err);
return database;
});
}
module.exports = db;
I icluded it to my server.js like this:
var db = require('./database');
but when I want to use it like this
db().collection('orders')
I am getting a TypeError (Cannot read property 'collection' of undefined)
Edit: sorry, I made an issue during writing this question of course I used db().collection
The issue is with your export, and misunderstood behavior of node's callbacks.
const MongoClient = require('mongodb').MongoClient;
const db = function(){
return MongoClient.connect('mongodb://localhost:27017/users', (err, database) => {
// this is inside a callback, you cannot use the database object outside this scope
if (err) return console.log(err);
return database; // this database object is what you should be exporting
});
}
module.exports = db; // You are exporting the wrong variable
One way to fix this is (may not be the best) to export the database object that we receive in the callback. Example:
const MongoClient = require('mongodb').MongoClient;
let database = null;
MongoClient.connect('mongodb://localhost:27017/users', (err, db) => {
if (err) return console.log(err);
database = db;
});
module.exports = database;
And now you can use the db, but with a null check.
var db = require('./database');
if (db !== null) {
db.collection('orders').find({}, (err, docs) => {
if (err) return console.log(err);
console.log(docs);
});
}
But this may lead to connection being established again and again when you require the database.js file (I am not sure about this). A better approach would be:
const MongoClient = require('mongodb').MongoClient;
let database = null;
const connect = () => {
if (database !== null) return Promise.resolve(database);
return new Promise((resolve, reject) => {
MongoClient.connect('mongodb://localhost:27017/users', (err, db) => {
if (err) return reject(err);
database = db;
resolve(database);
});
});
};
module.exports = connect;
and then use it like:
var dbConnect = require('./database');
dbConnect().then((db) => {
db.collection('orders').find({}, (err, docs) => {
if (err) return console.log(err);
console.log(docs);
});
}).catch((err) => {
console.error(err);
});

Categories