How to call a function that return the result of mysql query to send it back in a Express.js result? - mysql

How to call a function that return the result of MySQL query to send it back in a Express.js result?
I try to export some of my sql query in individual function to clean up and remove duplicate code.
I try with async await function, but it did not work.
How clean this code?
Thanks
import { Request, Response } from 'express'
import { mysqlConnection } from '../config/mysql.config'
import { users } from '../models/users.models'
export class AuthController {
constructor() { }
// I want to avoid this embedded callbacks function
public signin(req: Request, res: Response) {
var user: users = req.body
var insUser = [
user.userEmail,
user.userFirstName,
user.userLastName,
user.userEmail,
//hash password
// user.userPassword
]
mysqlConnection.pool.getConnection((err, connection) => {
connection.query('SELECT * FROM tblusers where userEmail = ? OR userUserName = ?', [user.userEmail, user.userUsername], (err, row: users[]) => {
if (err) throw err;
if (row.length) {
return res.status(400).json({ errors: { msg: "user exist already", status: 'signin-error' } })
}
//addUserInDB
connection.query('INSERT INTO tblusers (userUserName, userFirstName, userLastName, userEmail, userPassword) VALUES (? ,?, ?, ?, ?)', insUser, (err, row) => {
if (err) throw err;
//get userFormDB
connection.query('SELECT userId, userUsername, userFirstName, userLastName, userEmail, userPassword, webrName FROM tblusers INNER JOIN tblweblroles ON tblusers.tblWeblroles_webrId = tblweblroles.webrId where userEmail = ?', [user.userEmail], (err, row: users[], fields) => {
if (err) throw err
connection.release();
var firstUser = row[0]
var user = {
userId: firstUser.userId,
userUsername: firstUser.userUsername,
userFirstName: firstUser.userFirstName,
userLastName: firstUser.userLastName,
userEmail: firstUser.userEmail,
userUpdateAt: firstUser.userUpdateAt,
userCreatedAt: firstUser.userCreatedAt,
webrName: firstUser.webrName
}
res.status(200).json(user);
})
})
})
})
}
//test
private getUsers() {
console.log('test')
mysqlConnection.pool.query('SELECT * FROM webapp.tblusers;', (err: any, row: any) => {
if (err) throw err
console.log('row: ' + row)
return row
})
}
public async login(req: Request, res: Response) {
console.log('test1')
try {
var users = await this.getUsers()
console.log('users:' + users)
res.json(users);
} catch (error) {
res.json(error);
}
};
}

export class AuthController {
constructor() {
}
public async login(req: Request, res: Response) {
var users: any = await AuthController.getUsers()
res.json(users)
};
public static getUsers(): Promise<any> {
console.log('test')
return new Promise(resolve => {
mysqlConnection.pool.query('SELECT * FROM webapp.tblusers;', (err: any, row: any) => {
if (err) throw err
resolve(row)
})
});
}
}

Related

NodeJS with MySQL - Return blank Array

I have initialized an array "userTasklist". I have pushed the object in this array in .map function. After .map, I have console this Array but array is blank.
Than I have console the object in .map function and all the value print successfully but in Array there are no value. Don't know why.
exports.allUserList = (req, res) => {
let userID = req.params.userid;
const ghusersQuery = "SELECT user_id, name, employee_code FROM users WHERE under_gh = ?";
conn.query(ghusersQuery, [userID], (err, userdata) => {
if (err) {
res.send({ message: err })
} else {
if (userdata && userdata.length > 0) {
let userTasklist = [];
userdata.map((datauser) => {
var objtask = {};
const userDataQuery = "SELECT * FROM tasklist WHERE user_id = ?";
conn.query(userDataQuery, [datauser.user_id], (errnew, taskdata) => {
if (taskdata && taskdata.length > 0) {
objtask = {
userid: datauser.user_id,
tasklist: taskdata
}
userTasklist.push(objtask);
}
})
})
console.log(userTasklist)
res.send({ message: "user list fetched", userdata: userdata, tasklistdata: userTasklist })
} else {
res.send({ message: "Data not found!" })
}
}
})
}
Simplified solution using mysql21 for handling queries as Promises.
exports.allUserList = async (req, res) => {
const { userid } = req.params
const users = await connection.query('SELECT user_id, name, employee_code FROM users WHERE under_gh = ?', [userid])
if (!users.length)
return res.send({ message: "Data not found!" })
// better fetch all relevant tasks in bulk
const tasks = await connection.query('SELECT * FROM tasklist WHERE user_id IN (?)', [users.map(r => r.user_id)])
res.send({ message: "user list fetched", users, tasks })
}

MySQL Transactions in Node

Before I commit anything to the database, I want all my update promises resolve; otherwise, I rollback. In other words, I want atomicity. I suppose I could handle the rollback by deleting out rows, but this has its own risks. I noticed if there is an error in any of the promises, the data still gets updated in database. What am I doing wrong?
I have written a simple program to illustrate the issue.
This is the main process:
const db = require('./db.js');
const async = require('async');
let insertList = [];
for (let i = 0; i<3; i++) {
insertList.push(i);
}
async function func1 () {
return new Promise((resolve, reject) => {
console.log("In Func1");
async.forEachOf(insertList, function(value, key, callback) {
console.log('>>>>' + value + '<<<<<<' + key );
db.insertOne('coll1', {value}).then(() => {
callback();
}).catch(err => {callback(err)})
}, function(err) {
// if any of the file processing produced an error, err would equal that error
if( err ) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('err:', err);
reject(err);
} else {
console.log('Col1 All inserts have been processed successfully');
resolve("Success");
}
});
})
}
function func2 () {
return new Promise((resolve, reject) => {
console.log("In Func2");
async.forEachOf(insertList, function(value, key, callback) {
console.log('>>>>' + value + '<<<<<<' + key );
db.insertOne('coll2', {value}).then(() => {
callback();
}).catch(err => {callback(err)})
}, function(err) {
// if any of the file processing produced an error, err would equal that error
if( err ) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('err:', err);
reject(err);
} else {
console.log('Col2 All inserts have been processed successfully');
resolve("Success");
}
});
})
}
function func3 () {
return new Promise((resolve, reject) => {
console.log("In Func3");
async.forEachOf(insertList, function(value, key, callback) {
console.log('>>>>' + value + '<<<<<<' + key );
if(key === 1) {
value = 'a';
}
db.insertOne('coll3', {value}).then(() => {
callback();
}).catch(err => {callback(err)})
}, function(err) {
// if any of the file processing produced an error, err would equal that error
if( err ) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('err:', err);
reject(err);
} else {
console.log('Col3 All inserts have been processed successfully');
resolve("Success");
}
});
})
}
db.connect().then((pool) => {
pool.getConnection((err, connection) =>{
if (err)
return console.error(err);
else {
}
connection.beginTransaction((err) => {
if (err) {
return console.error(err);
}
let func1Promise = new Promise((resolve, reject) => {func1().then(() => {
console.log("Func1 complete");
resolve("Func1 complete");
}).catch((err) => {
console.error("Func1 ERROR: ", err);
reject("Func1 ERROR: ", err);
})});
let func2Promise = new Promise((resolve, reject) => {func2().then(() => {
console.log("Func2 complete");
resolve("Func2 complete");
}).catch((err) => {
console.error("Func2 ERROR: ", err);
reject("Func2 ERROR: ", err);
})});
let func3Promise = new Promise((resolve, reject) => {func3().then(() => {
console.log("Func3 complete");
resolve("Func3 complete");
}).catch((err) => {
console.error("Func3 ERROR: ", err);
reject("Func3 ERROR: ", err);
})});
Promise.all([func1Promise, func2Promise, func3Promise])
.then(()=> {
console.log("All Processes completed successfully.");
connection.commit(err => {
if (err) {
connection.rollback(() => {
throw err;
});
}
console.log('Commit Complete.');
connection.release();
});
})
.catch((err)=> {
console.error(err);
console.error("An update process has failed.");
connection.rollback(() => {
console.error(err);
connection.release();
});
})
});
})
});
The db.js looks like this:
const mysql = require('mysql');
const config = {
db: {
host: 'localhost',
user: process.env.DBUSER,
password: process.env.DBPASSWORD,
database: 'test',
}
};
var pool;
class DB {
constructor(host, user, password, database) {
this.host = host;
this.user = user;
this.password = password;
this.database = database;
}
connect() {
return new Promise((resolve, reject) => {
pool = mysql.createPool({
connectionLimit: 10,
host : this.host,
user : this.user,
password : this.password,
database : this.database
});
resolve(pool);
});
}
objToArray(obj) {
let arr = obj instanceof Array;
return (arr ? obj : Object.keys(obj)).map((i) => {
let val = arr ? i : obj[i];
if(typeof val === 'object' && val !== null)
return this.objToArray(val);
else
return val;
});
}
insertOne(collection, insertObj) {
return new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
if (err) {
resolve(err);
} else {
let sql = "INSERT INTO " + collection + " VALUES (?)";
// Convert the array of objects into an array of arrays.
let responseJson = this.objToArray(insertObj);
// The query object expects an array of objects so you pass in 'responseJson' as is
console.log(responseJson);
connection.query(sql, [responseJson], (err, result) => {
if (err) {
console.error(err);
return reject(err);
}
//console.log(result);
resolve("SUCCESS: object inserted into database");
});
}
});
});
}
}
const db = new DB(config.db.host, config.db.user, config.db.password, config.db.database);
Object.freeze(db);
module.exports = db;
My database "test" is simple and consists of 3 tables, coll1, coll2, coll3 and each has on field which is type int. In the third function I replace the 1 with 'a' This causes an error and the code catches this error and attempts a rollback, which does not work. If I set a breakpoint after func1 is executed and check the database, the values are already in the database.
Here is the version of MySQL that I am running:
Variable_name,Value
innodb_version,8.0.11
protocol_version,10
slave_type_conversions,
tls_version,"TLSv1,TLSv1.1,TLSv1.2"
version,8.0.11
version_comment,"MySQL Community Server - GPL"
version_compile_machine,x86_64
version_compile_os,macos10.13
version_compile_zlib,1.2.11
I am using the following NPM packages in node:
"async": "^2.6.2",
"mysql": "^2.15.0"
You're creating a transaction on a connection created in your test program, but your db.js's insertOne is grabbing a new connection from the pool that does not have a transaction. You should be passing in the connection you created in the test program.

mysql-js how to insert bulk records with an inserted id

My use case.
First I insert a single record to the grn_master table.
Then I get that insertedId to insert multiple records to the grn_detail table.
This is my code.
async function create(req, res, next) {
const grn = req.body.grn;
const supplier = req.body.supplier_id; //An object contains objects
const location = req.body.location;
try {
let query = "INSERT INTO grn_master SET customer_supplier_id = ?,location_id =?";
connection.query(query, [supplier, location], (error, results) => {
if (error) {
console.log(error);
res.sendStatus(500);
} else {
const grn_number = results.insertedId;
let query = "INSERT INTO grn_detail SET item_id=?,unit_price=?,qty=?,total=?,grn_master_id=??";
connection.query(query, [grn, grn_number], (error, results) => {
if (error) {
res.sendStatus(500);
console.log(error);
} else {
res.sendStatus(200);
}
})
}
})
} catch (error) {
console.log(error);
res.sendStatus(500);
}
}
How do I achieve this using Mysql-js

Query inside foreach Node.js Promis

i put query inside for each on promise. I am trying to query a mysql database twice, the second time, multiple times for each result from the first time but I am unable to work out how to wait for the result from the second query before continuing
i want the output like this :
{
"data":[
{
"name":"Title result",
"images":[
{
"id":1,
"place_id":705,
"path_image":"http://3.bp.blogspot.com/-iwF-ImFpzvk/T6fKhC6F7YI/AAAAAAAAARA/FyKpNcDsP8M/s1600/asd2e1.jpg"
},
{
"id":2,
"place_id":705,
"path_image":"https://asrt.bp.com/data/photo/2014/07/22/sddrfr2.jpg",
}
]
}
]
}
but i get only like this :
{
"data":[
{
"name":"Title result",
"images":[]
}
and this is my code:
return new Promise((resolve, reject) => {
const { connection, errorHandler } = deps;
let arrayData = [];
let imageData = [];
connection.query(
"SELECT * FROM places WHERE id = 705",
(error, rows, results) => {
rows.forEach((row) => {
connection.query(
"SELECT * FROM place_gallery WHERE place_id = 705",
(error, rows, results) => {
imageData = rows;
}
)
arrayData.push({ name: row.title, images: imageData })
});
if (error) {
errorHandler(error, "failed", reject);
return false;
}
resolve({ data: arrayData });
}
);
})
},
how to solve this?
try this, another way instated of creating dbcall function you can convert the query callback to promise using util.promisify()
const dbcall = (query) => {
return new Promise((resolve, reject) => {
connection.query(
query,
(error, rows, results) => {
if (error) return reject(error);
return resolve(rows);
});
});
};
const somefunc = async () => {
const {
connection,
errorHandler
} = deps;
let arrayData = [];
try {
const rows = await dbcall("SELECT * FROM places WHERE id = 705");
rows.forEach(async (row) => {
const imageData = await dbcall("SELECT * FROM place_gallery WHERE place_id = 705");
arrayData.push({
name: row.title,
images: imageData
});
});
} catch (error) {
console.log(error);
}
return arrayData;
}

Return MySQL result after query execution using node.js

I want to return the MySQL result into a variable.
I tried the following but it's not working, as I am getting an empty variable.
const mysql = require('mysql');
const db = require('../config/db');
const connection = mysql.createConnection(db);
module.exports = class Categories {
constructor (res) {
this.res = res;
}
getCategories() {
connection.query("SELECT * FROM `categories`", (error, results, fields) => {
if (error) throw error;
this.pushResult(results);
});
}
pushResult(value) {
this.res = value;
return this.res;
}
};
Just made a callback function first:
var Categories = {
getCategories: function (callback) {
connection.query("SELECT * FROM `categories`", (error, results, fields) => {
if(error) { console.log(err); callback(true); return; }
callback(false, results);
});
}
};
And then used it with route:
app.get('/api/get_categories', (req, res) => {
categories.getCategories(function (error, results) {
if(error) { res.send(500, "Server Error"); return; }
// Respond with results as JSON
res.send(results);
});
});