I'm creating my first app using Node.js and PostgreSQL.
This app connect's to db and return record to browser in JSON format, its work perfectly till i try to use map function to formating properties.
When i use map it return an error:
TypeError: rows.map is not a function
This is my code.
app.get('/car/:id', (req, res) => {
const car_id = req.params.id;
const queryString = `SELECT * FROM cars WHERE car_id= ${car_id}`;
client.query(queryString, (err, rows, fields) => {
if (err) {
console.log(err.stack);
res.sendStatus(500);
res.end();
} else {
const car = rows.map((row) => {
return {"Car_ID": row.car_id}
});
res.json(car);
console.log(rows.rows);
}
});
It should be result.rows not just rows
According to this - https://node-postgres.com/api/result
app.get('/car/:id', (req, res) => {
const car_id = req.params.id;
const queryString = `SELECT * FROM cars WHERE car_id= ${car_id}`;
client.query(queryString, (err, result, fields) => {
if (err) {
console.log(err.stack);
res.sendStatus(500);
res.end();
} else {
const car = result.rows.map((row) => {
return {"Car_ID": row.car_id}
});
res.json(car);
console.log(result.rows);
}
});
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 2 functions... 1st one in auth.js, which does this:
const adminCheck = (req, res) => {
console.log(“one”)
UtilRole.roleCheck(req, res, ‘ADMIN’, (response) => {
if(response) {
return true
} else {
return false
}
})
}
module.exports = {
adminCheck
}
basically checks if the user is an admin in my table. that works, but I am trying to retrieve the boolean in my function in my index.js function, which is below.
router.get(‘/viewRegistration’, auth.ensureAuthenticated, function(req, res, next) {
console.log("authcheck: " + auth.adminCheck())
const user = JSON.parse(req.session.passport.user)
var query = “SELECT * FROM tkwdottawa WHERE email = ‘” + user.emailAddress + “’”;
ibmdb.open(DBCredentials.getDBCredentials(), function (err, conn) {
if (err) return res.send(‘sorry, were unable to establish a connection to the database. Please try again later.’);
conn.query(query, function (err, rows) {
if (err) {
Response.writeHead(404);
}
res.render(‘viewRegistration’,{page_title:“viewRegistration”,data:rows, user});
return conn.close(function () {
console.log(‘closed /viewRegistration’);
});
});
});
})
where I am logging the value in the console.log right under where I initialize the function, it is returning undefined. how can I fix this?
You need to use Promise and wrap all callbacks to actually return a given result value from a function that uses a callback because usually a callback is called asynchronously and simply returning a value from it does not help to catch it in a calling function.
const adminCheck = (req, res) => {
console.log(“one”)
return new Promise(resolve, reject) => {
UtilRole.roleCheck(req, res, ‘ADMIN’, (response) => {
if(response) {
resolve(true)
} else {
resolve(false)
}
})
}
});
then you need to await a result calling this function using await keyword and marking a calling function as async:
router.get(‘/viewRegistration’, auth.ensureAuthenticated, async function(req, res, next) {
console.log("authcheck: " + await auth.adminCheck())
const user = JSON.parse(req.session.passport.user)
var query = “SELECT * FROM tkwdottawa WHERE email = ‘” + user.emailAddress + “’”;
ibmdb.open(DBCredentials.getDBCredentials(), function (err, conn) {
if (err) return res.send(‘sorry, were unable to establish a connection to the database. Please try again later.’);
conn.query(query, function (err, rows) {
if (err) {
Response.writeHead(404);
}
res.render(‘viewRegistration’,{page_title:“viewRegistration”,data:rows, user});
return conn.close(function () {
console.log(‘closed /viewRegistration’);
});
});
});
})
That's simple. You just forgot to return the inner function's return value
const adminCheck = (req, res) => {
console.log(“one”)
return UtilRole.roleCheck(req, res, ‘ADMIN’, (response) => {
if(response) {
return true
} else {
return false
}
})
}
module.exports = {
adminCheck
}
I've been reading about async and await in JS and tried to implement them in my code (which I totally messed up).
Here is my JS.
var express = require('express');
var router = express.Router();
var jsforce = require('jsforce');
const SEC_TOKEN = 'SEC_TOKEN';
const USER_ID = 'USER_ID';
const PASSWORD = 'PWD';
const { default: axios } = require('axios');
router.get("/", async (req, res, next) => {
await initConnect;
await soqlData;
await slackPostTest;
});
initConnect = async () => {
var conn = new jsforce.Connection({
loginUrl: 'https://login.salesforce.com'
});
await conn.login(USER_ID, PASSWORD + SEC_TOKEN, (err, userInfo) => {
if (err)
console.log(err);
else {
console.log(userInfo.Id);
}
});
}
soqlData = async () => {
await conn.query('Select Id, Name from Account LIMIT 1', (err, data) => {
if (err)
console.log(err);
else
return data.records[0];
})
}
slackPostTest = async () => {
await axios.post('SLACK_WEBHOOK', {
"text": "soqlRes"
})
}
module.exports = router;
What I am trying to achieve?
Initialize my connection by passing in SEC_TOKEN, USER_ID, PASSWORD to my initConnect function this will give me a connection (conn).
Use this conn and query my salesforce instance and get some other data.
post some message(currently irrelevant, but will hook up with the above response later) to my slack endpoint.
Also can someone please give me a little detailed explanation of the solution (in terms of async/await)?
Thanks
Assuming everything else about your JsForce API usage was correct (I have no experience with it, so I can't say), here's how to promisify those callback-based APIs and call them.
var express = require("express");
var router = express.Router();
var jsforce = require("jsforce");
const SEC_TOKEN = "SEC_TOKEN";
const USER_ID = "USER_ID";
const PASSWORD = "PWD";
const { default: axios } = require("axios");
router.get("/", async (req, res, next) => {
const { conn, userInfo } = await initConnect();
const data = await soqlData(
conn,
"Select Id, Name from Account LIMIT 1",
);
await slackPostTest(data.records[0]);
});
function initConnect() {
const conn = new jsforce.Connection({
loginUrl: "https://login.salesforce.com",
});
return new Promise((resolve, reject) => {
conn.login(USER_ID, PASSWORD + SEC_TOKEN, (err, userInfo) => {
if (err) return reject(err);
resolve({ conn, userInfo });
});
});
}
function soqlData(conn, query) {
return new Promise((resolve, reject) => {
conn.query(query, (err, data) => {
if (err) return reject(err);
resolve(data);
});
});
}
function slackPostTest(soqlRes) {
return axios.post("SLACK_WEBHOOK", {
text: soqlRes,
});
}
module.exports = router;
I am trying to use an api to get the current value of a stock and multiply by the users stock.
When I make a call the route I get empty data, and when I print the value of the callback I get an empty array
function user_cur_portfolio(port, callback) {
let portfolio = [];
port.forEach( (stock) => {
var ticker = stock.name.toLowerCase();
alpha.data.quote(`${ticker}`).then(data => {
var fixed = Number((data['Global Quote']['05. price'] * stock.shares).toFixed(2));
let curr = {
name : ticker,
shares: stock.shares,
value : fixed
}
portfolio.push(curr)
});
})
callback(portfolio)
}
router.get('/portfolio', (req, res, next) => {
if (req.session.userId !== undefined){
User.findOne({ _id : req.session.userId }).exec(function (err, user) {
if (err)
next(err);
user_cur_portfolio(user.portfolio, (port)=>{
console.log(port);
res.render('portfolio', { portfolio: port, balance: user.balance});
});
})
} else {
res.redirect('/users/login');
}
});
When I make a call the route I get empty data Because alpha.data.quote is an async function and forEach is a sync function therefore, you will not be getting data in port variable.
So the best work around to this, is to use async await with all the synchronous function to behave them like async
async function user_cur_portfolio(port) {
let portfolio = [];
await Promise.all(
port.map(async stock => {
var ticker = stock.name.toLowerCase();
const data = await alpha.data.quote(`${ticker}`);
var fixed = Number((data['Global Quote']['05. price'] * stock.shares).toFixed(2));
let curr = {
name: ticker,
shares: stock.shares,
value: fixed
};
portfolio.push(curr);
})
);
return portfolio;
}
router.get('/portfolio', (req, res, next) => {
if (req.session.userId !== undefined) {
User.findOne({ _id: req.session.userId }).exec(async function(err, user) {
if (err) next(err);
const port = await user_cur_portfolio(user.portfolio);
console.log(port);
res.render('portfolio', { portfolio: port, balance: user.balance });
});
} else {
res.redirect('/users/login');
}
});