I'm using MySQL2 to connect my Node.js app with a MySQL Database.
Unfortunately trying to perform some promise based prepared statements I just can't get a proper function setup that either returns successfully after entering the record or to throw an error whenever something goes wrong.
Any ideas on how to fix the code below?
// Connection Settings
const connection = mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
port: process.env.DB_PORT
})
// Promise based SQL Prepared Statement
db.pps = ({ query, variables, error }) => {
return new Promise((resolve, reject) => {
connection.execute(query, variables, (err, results) => {
if (err) {
console.log(`Error: ${error} \n ${err.sqlMessage}`)
return reject(err)
}
return resolve(results)
})
})
}
// Sign Up
auth.signup = (req, res) => {
const query = `
INSERT INTO User (Id, Email, Password)
VALUES (UUID_TO_BIN(UUID()), ?, ?)
`
const variables = [req.query.email, req.query.password]
db.promise({ query, variables }, (err, result) => {
if (err) {
res.status(400)
}
res.status(200)
})
}
you can use the prepared statement query function like below.
If you are not using this inside a function
auth.signup = (req, res) => {
const query = `
INSERT INTO User (Id, Email, Password)
VALUES (UUID_TO_BIN(UUID()), ?, ?)
`
const variables = [req.query.email, req.query.password]
db.pps({ query, variables })
.then(result => {
res.status(200)
})
.catch( error => {
res.status(400)
});
}
Or use async await
auth.signup = async (req, res) => {
const query = `
INSERT INTO User (Id, Email, Password)
VALUES (UUID_TO_BIN(UUID()), ?, ?)
`
const variables = [req.query.email, req.query.password]
try {
await db.pps({ query, variables });
res.status(200)
} catch (err) {
res.status(400)
}
}
You have to do 2 changes:
1.Remove error param
db.pps = ({ query, variables}) => {
2. Change the SignUp code as below
auth.signup = (req, res) => {
const query = `
INSERT INTO User (Id, Email, Password)
VALUES (UUID_TO_BIN(UUID()), ?, ?)
`
const variables = [req.query.email, req.query.password]
db.pps({ query, variables }).then(response => {
// Do stuff with users
})
.catch(err => {
// handle errors
})
function pps( query, variables){
return new Promise((resolve, reject) => {
connection.execute(query, variables, (err, results) => {
if (err) {
console.log(`Error: ${error} \n ${err.sqlMessage}`)
reject(err)
}
resolve(results)
})
})
}
auth.signup = (req, res) => {
const query = `
INSERT INTO User (Id, Email, Password)
VALUES (UUID_TO_BIN(UUID()), ?, ?)
`
const variables = [req.query.email, req.query.password]
pps(query, variables)
.then(result => {
res.status(200)
})
.catch( error => {
res.status(400)
});
}
Related
How to pass id in where clause using node.js and MySQL?
Viewer.jsx
async function redeem(cid) {
fetch('http://localhost:4000/getDetailsFromCid/${cid}').then(response => {
return response.json()
})
.then(posts => {
console.log("posts", posts)
})
.then((err) => {
console.log(err);
})
}
index.js
app.get("/api/getDetailsFromCid/:cid", (req, res) => {
const cid = req.params.cid;
db.query("SELECT * FROM Details WHERE cid = ?", [cid],
(err, result) => {
if (err) {
console.log(err)
}
res.send(result)
});
});
Error
Viewer.jsx:19 GET http://localhost:4000/getDetailsFromCid/$%7Bcid%7D 404 (Not Found)
you need to use `` not ''
fetch(`http://localhost:4000/getDetailsFromCid/${cid}`)
I'm having issues converting this setup: https://github.com/WebDevSimplified/Nodejs-Passport-Login
to push and pull user data from a mysql database. I've got the registration to work just fine, but I appear to be having difficulty with the login portion. I converted this portion from lines 14-18 of server.js
initializePassport(
passport,
email => users.find(user => user.email === email),
id => users.find(user => user.id === id)
)
to look like this
initializePassport(
passport,
email => db.getConnection( async (err, connection) => {
if (err) throw (err)
const sqlSearch = "SELECT * FROM users WHERE email = ?"
const searchQuery = mysql.format(sqlSearch, [email])
await connection.query(searchQuery, async (err, result) => {
connection.release()
if (err) throw (err)
console.log(result[0].email)
return result[0].email
})
}),
id => db.getConnection( async (err, connection) => {
if (err) throw (err)
const sqlSearch = "SELECT * FROM users WHERE id = ?"
const searchQuery = mysql.format(sqlSearch, [id])
await connection.query(searchQuery, async (err, result) => {
connection.release()
if (err) throw (err)
console.log(result[0].id)
return result[0].id
})
})
)
Basically, the initial setup found the relevant data from an array called "users", so I figured I could do the same with the mysql database. I have not changed the passport-config.js file, as I figured it didn't need it, but now I'm not so sure.
During login, the terminal logs the correct input email on login as per my modifications, but it never gets to the id portion of this. Also, it throws the programmed message "No user with that email" as found in line 8 of passport-config.js.
The rest of the code I have in my file is basically the same except for the database connection which looks like this (all the stuff references a .env file that has all the correct params):
const DB_HOST = process.env.DB_HOST
const DB_USER = process.env.DB_USER
const DB_PASSWORD = process.env.DB_PASSWORD
const DB_DATABASE = process.env.DB_DATABASE
const DB_PORT = process.env.DB_PORT
const mysql = require("mysql")
const db = mysql.createPool({
connectionLimit: 100,
host: DB_HOST,
user: DB_USER,
password: DB_PASSWORD,
database: DB_DATABASE,
port: DB_PORT
})
and the registration post method which looks like this:
app.post('/register', checkNotAuthenticated, async (req, res) => {
try {
const id = Date.now().toString()
const fName = req.body.firstName
const lName = req.body.lastName
const email = req.body.email
const password = await bcrypt.hash(req.body.password, 10)
db.getConnection( async (err, connection) => {
if (err) throw (err)
const sqlSearch = "SELECT * FROM users WHERE fName = ?"
const searchQuery = mysql.format(sqlSearch, [fName])
const sqlInsert = "INSERT INTO users VALUES (?,?,?,?,?)"
const insertQuery = mysql.format(sqlInsert,[id, fName, lName, email, password])
await connection.query (searchQuery, async (err, result) => {
if (err) throw (err)
console.log("------> Search Results")
console.log(result.length)
if (result.length != 0) {
connection.release()
console.log("------> User already exists")
}
else {
await connection.query (insertQuery, (err, result)=> {
connection.release()
if (err) throw (err)
console.log ("--------> Created new User")
console.log(result.insertId)
})
}
}) //end of connection.query()
}) //end of db.getConnection()
res.redirect('/login')
} catch {
res.redirect('/register')
}
})
As I said, I have no issues with the registration. The connection is successful, and subsequent inspection of the users table in the mysql terminal (I'm using Mac), the data is being stored correctly. How do I proceed here?
Looks like an issue with the return in initializePassport function.
When you return result[0].email or return result[0].id it returns out of the inner callback function of connection.query() not the outer function.
This may fix it:
initializePassport(
passport,
(email) =>
db.getConnection(async (err, connection) => {
if (err) throw err;
const sqlSearch = "SELECT * FROM users WHERE email = ?";
const searchQuery = mysql.format(sqlSearch, [email]);
// return out of db.getConnection()
return connection.query(searchQuery, async (err, result) => {
connection.release();
if (err) throw err;
console.log(result[0].email);
// return out of connection.query()
return result[0].email;
});
}),
(id) =>
db.getConnection(async (err, connection) => {
if (err) throw err;
const sqlSearch = "SELECT * FROM users WHERE id = ?";
const searchQuery = mysql.format(sqlSearch, [id]);
// return out of db.getConnection()
return connection.query(searchQuery, async (err, result) => {
connection.release();
if (err) throw err;
console.log(result[0].id);
// return out of connection.query()
return result[0].id;
});
})
);
i have an async function that takes a bearer token sent from headers.authorization and returns the current connected user information.
exports.me = async (req, res) => {
const accessToken = req.headers.authorization;
const bearer = accessToken.split(" ");
const bearerToken = bearer[1];
req.token = bearerToken;
// header take
jwt.verify(bearerToken, process.env.SECRET_KEY, function (err, decoded) {
if (decoded) {
const now = new Date();
User.findOne({ _id: decoded.id })
.select("firstName lastName email avatar birthday _id")
.then((user) => {
return res.status(200).json(user);
})
.catch((err) => {
return res.status(404).json(err);
});
}
});
};
instead of requesting req.params.userId from the front in the next function, i want to get the userId directly from the 'me()' function
exports.getEvents = async (req, res) => {
const allEvents = await Events.find({ owner: req.params.userId })
.then((events) => {
return res.status(200).json(events);
})
.catch((err) => {
return res.status(404).json(err);
});
};
Issue fixed by setting the id in the req.body and passing the me function as a middleware
User.findOne({ _id: decoded.id })
.select("firstName lastName email avatar birthday _id")
.then((user) => {
req.body.userId = user._id
next();
})
This is the very basic route I am using:
router.get('/:date', async (req, res) => {
let tracks = []
let query = 'SELECT * from `tracks` where `playlistDate` = \''+req.params.date+'\''
let result = await pool.query(query)
console.log(result)
})
I know this by itself won't work, but what do I need to do to be able to use await on the query function like this?
This is the pool, with the credentials and addr changed.
var pool = mysql.createPool({
poolLimit : 10,
host : 'HOST',
user : 'USER',
password : 'PASS',
database : 'DB'
});
Maybe this logic would help. It depends on how you structured it.
var pool = mysql.createPool({
poolLimit : 10,
host : 'HOST',
user : 'USER',
password : 'PASS',
database : 'DB'
});
const getTracks = (date) => {
return new Promise((resolve, reject) => {
let query = 'SELECT * FROM tracks WHERE playlistDate = ?'
pool.query(query, [date], (err, res) => {
if (err) {
reject(err);
return;
}
resolve(res);
})
})
};
router.get('/:date', async (req, res) => {
try {
let tracks = await getTracks(req.params.date);
return res.status(200).json(tracks);
} catch (err) {
return res.status(400).json(err);
}
})
I need to register a new user, when receiving the parameters make a query using the city name to get the state and city id (both are foreign keys). I implemented a function to find the ids. Inside the function using data.id the id is returned correctly. But at the time of insert in database is being inserted "undefined".
Apparently the save operation is being executed before the findCity and findState functions return the value.
execution flow
cidade = city, estado = city
module.exports = app => {
const obterHash = (senha, callback) => {
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(senha, salt, null, (err, hash) => callback(hash))
})
}
var idCidade;
var idEstado
function findCidade(cidade, ) {
app.db('cidades')
.where({ nome: cidade })
.first()
.then(data => {
idCidade = data.id
console.log('inside findCity. data.id: '+data.id)
}).catch((err) => console.log("erro cidade", err));
return
}
function findEstado(uf) {
app.db('estados')
.where({ uf: uf })
.first()
.then(data => {
idEstado = data.id
console.log('inside findState. data.id: '+data.id)
}).catch((err) => console.log("erro estado", err));
}
const save = (req, res) => {
console.log("\n")
findCidade(req.body.cidade)
findEstado(req.body.uf)
obterHash(req.body.senha, hash => {
const senha = hash
console.log("Will be inserted. idCity: "+idCidade+" idState: "+idEstado)
app.db('salao')
.insert({ idcidade: idCidade,
idestado: idEstado,
senha})
.then(_ => res.status(200).send())
.catch(err =>{res.status(400).json(err)})
})
}
return { save }
}
I'm from Brazil and I'm using a translator, sorry for the spelling mistakes.
You are welcome to the asynchronous world!
General explanation: You are going to use results of a database querying before it will happen. Your program have to wait the results (idCidade, idEstado) before you can use it. Because of it you can find the record Will be inserted... first in your logs.
For the explanation I'm going to use Minimal Reproducible Example.
function findCidade(cidade) {
return Promise.resolve(1);
}
function findEstado(uf) {
return Promise.resolve(1);
}
Promise.all([findCidade(), findEstado()])
.then((data) => console.log(data));
The output is:
[ 1, 1 ]
To solve the issue you have to:
Return the promise explicitly with return statement.
Await the results by async/await or Promise interface methods. Or use callbacks if it is more suitable to you.
module.exports = app => {
const obterHash = (senha, callback) => {
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(senha, salt, null, (err, hash) => callback(hash))
})
};
function findCidade(cidade, ) {
return app.db('cidades')
.where({ nome: cidade })
.first()
.then(data => {
idCidade = data.id
console.log('inside findCity. data.id: '+data.id)
}).catch((err) => console.log("erro cidade", err));
}
function findEstado(uf) {
return app.db('estados')
.where({ uf: uf })
.first()
.then(data => {
idEstado = data.id
console.log('inside findState. data.id: '+data.id)
}).catch((err) => console.log("erro estado", err));
}
const save = (req, res) => {
console.log("\n");
Promise.all([findCidade(req.body.cidade), findEstado(req.body.uf)])
.then((data) => {
const [idCidade, idEstado] = data;
obterHash(req.body.senha, hash => {
const senha = hash;
console.log("Will be inserted. idCity: "+idCidade+" idState: "+idEstado);
app.db('salao')
.insert({ idcidade: idCidade,
idestado: idEstado,
senha})
.then(_ => res.status(200).send())
.catch(err =>{res.status(400).json(err)})
})
})
.catch((err) => console.log("general error", err));
};
return { save }
}