How to add Promise value in render() in node js - mysql

router.get('/top-website', function (req, res, next) {
// console.log(topSites)
connection.query("SELECT * FROM topsites LIMIT 5", function (err, results, fields) {
// const url =this.rootDomain;
results.forEach(function (item) {
console.log(item.rootDomain)
linkPreview(item.rootDomain)
.then(resp => {
console.log(resp)
res.render('top-website', { sitedata: results,fn:resp });
//console.log(resp)
})
})
})
})
i want to get value resp in render but im getting error,

Related

Mongoose updating and fetching in the same request

I have the following mongoose "update" path:
app.put('/update', async (req, res) => {
const newTaskName = req.body.todoName
const newDays = req.body.days
const id = req.body.id
try {
await TodoModel.findById(id, async (err, updatedTodo) => {
updatedTodo.todoName = newTaskName
updatedTodo.daysToDo = newDays
await updatedTodo.save()
res.send("updated")
})
} catch(err) {
console.log(err)
}
})
Separately I have a path that returns all data from the Mongo table:
app.get('/read', async (req, res) => {
TodoModel.find({}, (err, result) => {
if (err) {
res.send(err)
}
res.send(result)
})
})
How can I both update and send back the full updated list within the response?
Separate question, not necessary to answer, but would be nice - perhaps this approach is all wrong? some background:
In my MERN app I am calling to add an item to a list and then want to immediately render the updated list as currently read from the database, since I don't want to assume the insertion was successful
I tried using some asynchronous workarounds with no luck
Fixed!
Upon further inspection of Mongoose documentation, I found that by using the findOneAndUpdate method instead of findById, I am able to utilize a callback that will return the updated item:
app.put('/update', async (req, res) => {
const id = req.body.id
let updateSet = req.body
delete updateSet.id
try {
ShoppingModel.findOneAndUpdate({ _id: id }, { $set: updateSet }, { new: true }, (err, doc) => {
if (err) return console.log(err)
res.send(doc)
})
} catch (err) {
console.log(err)
}
})

Asynch problem when fetching MySQL and EXPRESS

I'm trying to simple add a new property in an object. The array of objs is being fetched from my database and then I try to add a property which is also fetched from my database. Although when I try to manipulate it I'm receiving "undefined".
Is it indeed an asynch problem?
Am I doing any silly mistakes?
Those are questions that surrounds my head at the moment.
Code:
exports.getIndex = (req, res, next) => {
Report.fetchAll().then(([rows, fieldData]) => {
// console.log(rows);
const modifiedRows = rows.map(el => {
Report.fetchUserNameOfReport(el.UserInfo_idPessoa).then(([rows, fieldData]) => {
console.log(rows);
return {
...el,
userOfReport: 'Joao' //change later to smthing like rows.name
};
}).catch(err => console.log(err));
// return{
// ...el,
// userOfReport: 'Joao'
// };
});
res.render('user/index', { reports: rows, pageTitle: 'Social Reporter', path: '/' });
}).catch(err => console.log(err));
};
Obs This works if comment this out and comment Report.fetchUserNameOfReport function->
// return{
// ...el,
// userOfReport: 'Joao'
// };
Expected result:
{
idComplaint: 83059,
title: '4444',
description: '4444',
image: '4444',
location: '4444',
UserInfo_idPessoa: 80068,
userOfReport: 'Joao'
}
Actual result:
undefined
Thank you in advance!
You never return anything in your .map, so all of the values of modifiedRows will be undefined. You can map them all to promises to get all the values, and then access the modified rows once you wait for all of the promises to resolve. Also, you're shadowing your variable by declaring rows and fieldData multiple times:
exports.getIndex = (req, res, next) => {
Report.fetchAll().then(([rows, fieldData]) => {
// console.log(rows);
const modifiedRowPromises = rows.map(el => {
return Report.fetchUserNameOfReport(el.UserInfo_idPessoa).then(([rows2, fieldData2]) => {
console.log(rows2);
return {
...el,
userOfReport: 'Joao' //change later to smthing like rows2.name
};
});
});
Promise.all(modifiedRowPromises).then(modifiedRows => {
res.render('user/index', { reports: modifiedRows, pageTitle: 'Social Reporter', path: '/' });
}).catch(console.log);
}).catch(err => console.log(err));
};
Alternatively, if you use async/await syntax, this can be achieved much more cleanly:
exports.getIndex = async (req, res, next) => {
try {
const [rows, fieldData] = Report.fetchAll();
const modifiedRowPromises = rows.map(async el => {
const [rows2, fieldData2] = await Report.fetchUserNameOfReport(el.UserInfo_idPessoa);
return {
...el,
userOfReport: 'Joao' //change later to smthing like rows2.name
};
});
const modifiedRows = await Promise.all(modifiedRowPromises);
res.render('user/index', { reports: modifiedRows, pageTitle: 'Social Reporter', path: '/' };
} catch (err) {
console.log(err);
}
};

Returning undefined from mySQL

I know the database is connecting with the code as, when i console.log(res) with the code below it is returning the correct data,
const orm={
selectAll(){
connection.query('SELECT * FROM burgers', (err,res) => {
if (err) throw err;
console.log(res)
return res;
});
},
Yet when i console.log(burgers) from this function in the code below it is returning an undefined
app.get(`/`, function (req, res) {
const burgers = orm.selectAll();
console.log(burgers)
res.render(`index`, burgers);
});
I understand this may be a very simple answer but i personally just cannot work it out any help is welcomed.
selectAll is using a callback style method inside it. You can not get the response syncronously. You need to either pass the callback to selectAll or change it to use promise like this
function selectAll() {
return new Promise((reoslve, reject) => {
connection.query("SELECT * FROM burgers", (err, res) => {
if (err) {
reject(err);
}
reoslve(res);
});
});
}
You can then use it like this
app.get(`/`, function async (req, res) {
const burgers = await selectAll();
console.log(burgers)
res.render(`index`, burgers);
});
Your selectAll method will not return any value.
query get an lambda callback function as second parameter AND query is asyncron
One way is to return an Promise from selectAll
const orm = {
selectAll(callback) {
return new Promise((resolve, reject) => {
connection.query('SELECT * FROM burgers', (err, res) => {
if (err) {
reject(err);
} else {
resolve(res)
}
})
})
},
Than you can get your result:
app.get(`/`, function (req, res) {
orm.selectAll().then( burgers => {
console.log(burgers)
res.render(`index`, burgers);
});
});

custom validation (Existing email)

I wanted to use express-validator to check if the email exists
here is my code:
router.post('/', [
check('username', 'Min 5 chars, Max 20').isLength({ min: 5, max: 20 }),
check('email').custom(async value => {
const db = require('../db');
return await db.query('SELECT id FROM users WHERE email=?', [value], function (err, results, fields) {
if (results.length > 0) {
return false;
} else { return true; }
})
}).withMessage('Email already exists'),
], function(req, res, next) {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
....
The problem with async/await that the validation didnt execute at all even if the return is true or false. How to fix it?
You are using bad async/await commands. And to be honest, you don't need them here.
router.post('/', [
check('username', 'Min 5 chars, Max 20').isLength({ min: 5, max: 20 }),
check('email').custom(value => {
const db = require('../db');
return new Promise((resolve, reject) => {
db.query('SELECT id FROM users WHERE email=?', [value], function (err, results, fields) {
if (err)
reject(err)
if (results.length>0)
reject(new Error('Email Already exists'))
resolve()
})
})
}),
], function(req, res, next) {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}

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);
});
});