In an Express JS connected to a mySQL db, I am trying to get some data of an already defined route/ query:
// customers.model.js
CUSTOMERS.getAll = (result) => {
let query = "SELECT * FROM customers"
sql.query(query, (err, res) => {
if (err) {
console.log("error: ", err)
result(null, err)
return
}
result(null, res)
})
}
// customers.controller.js
// GET customers is a standalone route and should output all the customers when called.
const CUSTOMERS = require("../models/customers.model.js")
exports.findAll = (req, res) => {
return CUSTOMERS.getAll((err, data) => {
if (err)
res.status(500).send({
message: err.message ||
"Some error occurred while retrieving customers...",
})
else res.send(data)
})
}
In payments.controller.js I would firstly like to get all users so I can do something with the data:
// payments.controller.js
// GET payments is also a standalone route and should get the customers,
// do something with the data and output a calculation with the help of this data
const CUSTOMERS = require("../models/customers.model.js")
exports.calculateAll = (req, res) => {
const customers = CUSTOMERS.getAll((err, data) => {
console.log('this always has correct data', data)
if (err) return err
else return data
})
console.log('this is always undefined', customers)
...
res.send(whatEverCalculatedData)...
}
But that data here is always undefined.
What am I doing wrong in the above, and what's the correct way to call this route inside another route?
I know it has similarities with this question but I couldn't sort it out for my particular example.
It's due to your call which is asynchronous.
You must wait your data being ready before rendering the results.
Maybe you could to use Promises or async/await statements.
For example:
CUSTOMERS.getAll = async () => {
const query = "SELECT * FROM customers";
try {
return await sql.query(query);
} catch (e) {
console.log(`An error occurred while fetching customers: ${e.message}.`);
return null;
}
}
exports.calculateAll = async (req, res) => {
try {
const data = await CUSTOMERS.getAll();
res.send(whatEverCalculatedData);
} catch (e) {
res.send(`Something went wront: ${e.message}.`);
}
}
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);
}
});
I'm trying to pass a function ereaseFiles() before the upload.array() method is called but I can't figure out how to make it.
The main goal is with a put request to delete all files on disk related to that object before of uploading new ones.
I've tried to set the function in the diskStorage section as well as in the callback of the put route. I even tried handling it in the function itself before the upload.array() method was called. I've tried working with promises but that is way too hard for me.
//function to be called (this works)
function ereaseFiles(req) {
glob("uploads/" + req.body.numeroScheda + "*", function (err, files) {
for (const file of files) {
fs.unlink(file, err => {
if (err) throw err;
console.log('successfully deleted files');
});
}
});
}
//My multer setup:
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads/');
},
filename: function (req, file, cb) {
cb(null, req.body.numeroScheda + "-" + file.originalname);
}
});
const upload = multer({
storage: storage, limits: {
fileSize: 1024 * 1024 * 2,
},
});
//MY EDIT PUT ROUTE
app.put("/immobili/:_id", upload.array('immaginePrincipale', 30), function (req, res) {
const requestedId = req.params._id;
const proprietaImmagini = req.files;
const immagini = proprietaImmagini.map(function (immagine) {
//console.log(immagine.path);
return immagine.path;
});
Immobile.findOneAndUpdate(requestedId, {
numeroScheda: req.body.numeroScheda,
categoria: req.body.categoria,
titolo: req.body.titolo,
sottotitolo: req.body.sottotitolo,
descrizione: req.body.descrizione,
localita: req.body.localita,
locali: req.body.locali,
superficie: req.body.superficie,
camere: req.body.camere,
bagni: req.body.bagni,
immagini: immagini,
}, function (err, updatedImmobile) {
if (err) return console.error(err);
res.redirect("/immobili/" + requestedId);
});
});
What should happen is that all files on disk associated with the object (numeroScheda) get deleted before the new ones are uploaded to keep the storage of files automated and clean.
EDIT 1:
I've created a delete route that works:
app.delete("/immobili/:_id", (req, res) => {
const requestedId = req.params._id;
Immobile.findOne({ _id: requestedId }, function (err, immobile) {
if (err) return console.error(err);
ereaseFiles(immobile);
});
Immobile.findOneAndRemove(requestedId, err => {
if (err) console.error(err);
else res.redirect('/immobili');
});
});
the function ereaseFiles looks now like this:
ereaseFiles = immobile => {
glob("uploads/" + immobile.numeroScheda + "*", function (err, files) {
for (const file of files) {
fs.unlink(file, err => {
if (err) throw err;
});
}
});
cancellato = true;
}
I've tried to implement this in the edit route with the middleware as kindly suggested with this:
app.use("/immobili/:_id", function (req, res, next) {
const requestedId = req.params._id;
let timer = setInterval(() => {
Immobile.findOne({ _id: requestedId }, (err, immobile) => {
if (err) return console.error(err);
ereaseFiles(immobile);
console.log(this.cancellato);
if (this.cancellato) {
clearInterval(timer);
next();
}
});
}, 1000);
});
This works if the uploaded pictures are more or same than before but if less it outputs with strange behaviors (sometimes it uploads some pictures, sometimes none).
You can use a middleware for that. Just make sure that the middleware is positioned before your put request handler.
app.use("/immobili/:_id", function(req,res,next){
eraseFiles(req);
let timer = setInterval(() => {
if(erased){
clearInterval(timer);
next();
}
},100);
})
app.put("/immobili/:_id", upload.array('immaginePrincipale', 30), function (req, res) { ...
EDIT 1:
Please change your eraseFiles function to:
function ereaseFiles(req) {
glob("uploads/" + req.body.numeroScheda + "*", function (err, files) {
for (let i=0;i<files.length-1;i++) {
fs.unlink(files[i], err => {
if (err) throw err;
console.log('successfully deleted files');
if(i===files.length-1)
erased = true;
});
}
});
}
Edit 2: Changed a lot of things. Now the approach is your route will go to the middleware first. Your eraseFiles function will be called. While the erased variable is not true, your put route will not be hit. When the erasedFiles function is complete it will set erased to true. For this to work, you'll have to set erased=false in the file before all this.
I won! The solution was to put a little timer on the next() function as it was firing too soon and the uploads and it was mixing the two. Thanks for your help everyone!
I've also added an ereased variable that turned off and on as the function completes. Thanks to Mr. Web for that.
Here's the answer if someone runs across this, there's some Italian in the code, hopefully is readable enough anyways!
cancellaFoto = immobile => {
cancellato = false;
glob("uploads/" + immobile.numeroScheda + "*", function (err, files) {
for (const file of files) {
fs.unlink(file, err => {
if (err) throw err;
});
}
});
cancellato = true;
}
app.use("/immobili/:_id", function (req, res, next) {
const requestedId = req.params._id;
Immobile.findOne({ _id: requestedId }, (err, immobile) => {
if (err) return console.error(err);
immobile.immagini = [];
cancellaFoto(immobile);
console.log(immobile.immagini);
if (this.cancellato) {
console.log(this.cancellato);
return setTimeout(next, 500);
} else {
return console.log("Aborted");
}
});
});
//EDIT PUT ROUTE
app.put("/immobili/:_id", upload.array('immaginePrincipale', 30), function (req, res) {
const requestedId = req.params._id;
const proprietaImmagini = req.files;
const immagini = proprietaImmagini.map(function (immagine) {
//console.log(immagine.path);
return immagine.path;
});
console.log(immagini);
Immobile.findOneAndUpdate(requestedId, {
numeroScheda: req.body.numeroScheda,
categoria: req.body.categoria,
titolo: req.body.titolo,
sottotitolo: req.body.sottotitolo,
descrizione: req.body.descrizione,
localita: req.body.localita,
locali: req.body.locali,
superficie: req.body.superficie,
camere: req.body.camere,
bagni: req.body.bagni,
immagini: immagini,
}, function (err, updatedImmobile) {
if (err) return console.error(err);
res.redirect("/immobili/" + requestedId);
});
});
Can anyone tell me why I get an undefined MessageList in export function and how to get a correct value? The two blocks are in a same file.
var MessageList;
var sql = require("mssql");
var config = {
//config
};
// connect to your database
sql.connect(config, function (err) {
if (err) console.log(err);
var request = new sql.Request();
request.query('select top 3 * from test', function (err, recordset) {
if (err) console.log(err)
MessageList = JSON.stringify(recordset);
console.log("MessageList in sql.connect:"+MessageList); //===> that's ok
});
});
The Problem is here:
exports.getMessageList = function (callback) {
console.log("MessageList in exports:"+MessageList); // ===> **MessageList here will show undefine**
callback(MessageList);
};
I'm trying to compare an entered email on my website, to ones in the database to see whether it already exists. If it does, then the function returns false and an error is displayed.
var db = new sqlite3.Database('users_db.db');
db.get(
"SELECT * FROM users WHERE useremail = ?",
[email],
function (err, rows) {
if (rows == undefined ){
global.returnvalue2 = false;
}
}
);
What I want is for the function to be run immediately after the selection, so that the returned value is false, and the user record is not created.
At the moment I realise that the callback is being called after everything, so its just making the selection and carrying on throughout the rest of the program until the end.
How can I check if there are any existing records with the same email?
Make use of the async features in javascript, so your code would look something like this;
var db = new sqlite3.Database('users_db.db');
function checkemail(email, cb) {
db.get(
"SELECT * FROM users WHERE useremail = ?",
[email],
function (err, rows) {
if (err || rows == undefined ){
cb("bad email", null)
} else {
cb(null,rows)
}
});
}
function checkpassword(pw,cb) {....}
function checkclass(cls,cb) {....}
and then write you code like this;
checkemail(myemail, function(err,rows) {
if (err) return alert(err);
checkpassword(pw, function(err, msg) {
if (err) return alert(err);
checkclass(cls, function(err, msg) {
if (err) return alert(err);
alert("Congratulation you passed all the checks");
});
});
});
Here's a little one I made.
const sqlite3 = require('sqlite3').verbose();
let db = new sqlite3.Database('iHacks.db');
function get_user_credentials (email, password)
{ return new Promise((rs, rj) => {
function callback (err, User)
{
if (err) rj(err);
rs(User);
}
db.get('select * from users where email=? and password=?', [email, password], callback);
}); }
function login (email, password)
{ return new Promise ((rs, rj) => {
// Hashing the password.
password = sha256(password + 'EzSalt');
// Creating an Error
const err = new Error('Email or password did not match!');
// Callback functions
function check (User)
{
rs(User);
}
function fail (err)
{
rj(err);
}
// Getting the user credentials
get_user_details(email, password).then(check).catch(fail);
}); }
login()
.then(/* Continue code */)
.catch(err => {throw new Error(err); })
;