How to deal with asynchrony? - node.js

I'm a C/C++ guy trying to make a simple web app using Node.js, Express.js and MariaDB.
function getData(sensor)
{
var query = c.query('SELECT * FROM sensor_data WHERE id >= ALL (SELECT id FROM sensor_data WHERE sensor = ?) AND sensor = ?', [sensor,sensor]);
query.on('result', function(res) {
res.on('data',function(row) {
return(row);
});
});
}
app.get('/', function(req, res) {
res.render('index', {
temperatureSala: getData('sala').temperature + 'ºC',
humiditySala: getData('sala').humidity + '%'
});
});
My problem is dealing with the asynchrony. When I try to render the page the render functions finishes running first and then I get that the variables are undefined. The query finishes after and the result is correct.
What is the best way of dealing with this?
Any question you have please ask.
Thank you!

You should structure your app.get like this. I have omitted your function getData but if you need it for later use then you can set it up in such a way that it takes a callback and execute res.render inside of that callback.
app.get('/', function(req, res) {
const query = c.query('SELECT * FROM sensor_data WHERE id >= ALL (SELECT id FROM sensor_data WHERE sensor = ?) AND sensor = ?', ['sala', 'sala']);
query.on('result', function(queryRes) {
queryRes.on('data',function(row) {
const temperatureSala = row.temperature + 'ºC',
humiditySala = row.humidity + '%';
res.render('index', {
temperatureSala,
humiditySala
});
});
});
});

Related

How could I force the execution of a function in Node.js?

I'm making a website in which I could learn the flags from all around the world. The idea is before the front is loaded, my back choose a random int, and pick a flag at this id from my database, and then display it in order then to try to guess the flag.
My problem is that my render is executed before my function which choose a random flag, so I can't display it.
How could I force the getRandomFlags function to be executed before the render of my ejs ? Is that really possible due to the Node.js principe or is there solutions ?
var maxIdDB;
var paysChoisi;
router.post('/', function (req, res) {
res.render("index.ejs",{extension: 'be.png'});
});
router.use('/', function (req, res) {
getRandomFlag();
res.render("index.ejs",{extension: 'fr.png'});
console.log('test');
});
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
function getRandomFlag() {
db.get('SELECT MAX(id) FROM Flags;', (err, row) => {
maxIdDB = row['MAX(id)'];
})
var randomInt = getRandomInt(maxIdDB);
const statement = db.prepare('SELECT * FROM Flags WHERE id=?;');
statement.get(randomInt, (err,result) => {
setCountry(result);
});
}
function setCountry(result) {
paysChoisi = result;
console.log('set');
}
I tried to load it anyway and refresh several times until my paysChoisi variable is defined but server and client were out of sync. I mean :
server : choose Japan
server : choose France
client : answered Japan
server : choose Kenya
client : answered France
The easiest solution here would be to use a callback
router.use('/', function (req, res) {
getRandomFlag(() => {
res.render("index.ejs",{extension: 'fr.png'});
console.log('test');
});
});
function getRandomFlag(callback) {
db.get('SELECT MAX(id) FROM Flags;', (err, row) => {
maxIdDB = row['MAX(id)'];
})
var randomInt = getRandomInt(maxIdDB);
const statement = db.prepare('SELECT * FROM Flags WHERE id=?;');
statement.get(randomInt, (err,result) => {
setCountry(result);
callback()
});
}
But it would be better if you would use promises

Can't get 'res.status(200).redirect('')' to work

I am working on a project that requires me to redirect the user to a new page after a mysql query. For some reason it works throughout the rest of the program but in this particular section, it just does nothing.
Here is my code that doesn't work.
No idea what im missing here...
exports.ad_dash_load = async (req, res) => {
var uid=req.body.User_id;
db.query('SELECT COUNT(*) AS `z`FROM `user`', async (error, results)=>{
if(error) {
console.log(error);
} else {
let user_count=results[0].z;
res.status(200).redirect("/admin?Id="+uid+"&user_count="+user_count);
}
})
}
So there are 2 other ways we can execute this query
OPTION 1
Save the result into a variable that comes from the query and then check if the var has the result
exports.ad_dash_load = async (req, res) => {
var uid = req.body.User_id;
const result = await db.query("SELECT COUNT(*) AS `z`FROM `user`");
if (!result) {
console.log(error);
} else {
let user_count = results[0].z;
res.status(200).redirect("/admin?Id=" + uid + "&user_count=" + user_count);
}
};
OPTION 2
Using this method is equivalent to using try catch block
Use .then().catch() block on the async db query
exports.ad_dash_load = async (req, res) => {
var uid = req.body.User_id;
db.query("SELECT COUNT(*) AS `z`FROM `user`")
.then((result) => {
let user_count = results[0].z;
res
.status(200)
.redirect("/admin?Id=" + uid + "&user_count=" + user_count);
})
.catch((err) => {});
};
Ok i think i understand the root of this problem....the "exports" function is supposed to be triggered from a Form POST on a previous page but because i was not moving from a page with a form i opted to use a javascript routine to send user id code to the "exports" function. This fact is responsible for the redirect not working. Trying to figure out another way around this.

How To Bind Node-js DB Query to Web Form

I'm using node and postgres, I'm new to writing async function, what I'm trying to do is a very simple query that will do a total count of records in the database, add one to it and return the result. The result will be visible before the DOM is generated. I don't know how to do this, since async function doesn't return value to callers (also probably I still have the synchronous mindset). Here's the function:
function generateRTA(callback){
var current_year = new Date().getFullYear();
const qry = `SELECT COUNT(date_part('year', updated_on))
FROM recruitment_process
WHERE date_part('year', updated_on) = $1;`
const value = [current_year]
pool.query(qry, value, (err, res) => {
if (err) {
console.log(err.stack)
} else {
var count = parseInt(res.rows[0].count) + 1
var rta_no = String(current_year) + '-' + count
callback(null, rta_no)
}
})
}
For the front-end I'm using pug with simple HTML form.
const rta_no = generateRTA(function (err, res){
if(err){
console.log(err)
}
else{
console.log(res)
}
})
app.get('/new_application', function(req, res){
res.render('new_application', {rta_number: rta_no})
});
I can see the rta_no in console.log but how do I pass it back to the DOM when the value is ready?
Based on the ajax call async response, it will update the div id "div1" when it gets the response from the Node js .
app.js
app.get("/webform", (req, res) => {
res.render("webform", {
title: "Render Web Form"
});
});
app.get("/new_application", (req, res) => {
// Connect to database.
var connection = getMySQLConnection();
connection.connect();
// Do the query to get data.
connection.query('SELECT count(1) as cnt FROM test ', function(err, rows, fields) {
var person;
if (err) {
res.status(500).json({"status_code": 500,"status_message": "internal server error"});
} else {
// Check if the result is found or not
if(rows.length==1) {
res.status(200).json({"count": rows[0].cnt});
} else {
// render not found page
res.status(404).json({"status_code":404, "status_message": "Not found"});
}
}
});
// Close connection
connection.end();
});
webform.pug - Via asynchronous call
html
head
script(src='https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js')
script.
$(document).ready(function(){
$.ajax({url: "/new_application", success: function(result){
$("#div1").html(result.count);
}});
});
body
div
Total count goes here :
#div1
value loading ...
That seems okay, I'm just not sure of this:
The result will be visible before the DOM is generated
This constraint defeats the purpose of async, as your DOM should wait for the returned value to be there. Instead of waiting for it you could just render the page and once the function returns and runs your callback update the value.
Also, perhaps it's worth having a look into promises

node js returning mysql data to variables

I'm trying to use node js and mysql, along with rendering data from my database into a view.
The issue is, how do I render multiple pieces of data within 1 view (Using jade template).
router.get('/about', function(req, res) {
var animalsData = sequelize.query("SELECT * FROM animals").success(function(rows) {
return rows;
});
console.log(animals); // returns 'undefined'
var humansData = sequelize.query("SELECT * FROM humans").success(function(rows) {
return rows;
});
console.log(humans); // returns 'undefined'
res.render('about', { animals: animalsData, humans: humansData });
});
As you can see, how can I get the data and then pass it into the view? Using nested callbacks can get messy if theres 5 or 6 bits of data (mysql queries) I wish to pass into the view?
Thanks
First of, those returns don't work. The code that you are running is asynch. I would suggest you to use promises:
var q = require("q");
router.get('/about', function(req, res) {
var animalDeferer = q.defer(),
humanDeferer = q.defer;
sequelize.query("SELECT * FROM animals").success(function(rows) {
animalDeferer.resolve(rows);
});
sequelize.query("SELECT * FROM humans").success(function(rows) {
humanDeferer.resolve(rows);
});
Q.all([animalDeferer.promsie, humanDeferer.promise]).spread( function(animalsData, humansData) {
res.render('about', { animals: animalsData, humans: humansData });
});
});
I wrote this directly on the answerbox so it may have typos.
q - https://github.com/kriskowal/q

exporting a module in a callback function?

is there a way to export some variables that are inside a callback function? for example, if i need to use room.room_id in another file, what should i do? i tried module.exports.roomId = room.room_id but roomId in another file appeared to be undefined.thanks!
var Room = require('../models/database').Room
exports.create = function (req, res) {
Room
.create({
room_name: req.body.roomName
})
.complete(function () {
Room
.find({where: {room_name: req.body.roomName}})
.success(function (room) {
// if(err) console.log(err);
res.redirect('rooms/videochat/' + req.body.roomName + '/' + room.room_id);
console.log("room_id: " + room.room_id);
module.exports.roomId = room.room_id;
})
})
};
You can't do it like that because modules are evaluated synchronously and you're mutating module.exports some time in the future. What you need to do is supply a callback and either pass the value in or use the callback as an indicator that you can successfully read from the exported property.
This is not the best way to solve this problem, because modules are read once synchronously and cached but your code seems to handle requests and responses.
You will want rather export something like this:
var rooms = {};
exports.create = function (req, res, next) {
Room.create({
room_name: req.body.roomName
}).complete(function () {
Room.find({where: {room_name: req.body.roomName}})
.success(function (room) {
res.redirect('rooms/videochat/' + req.body.roomName + '/' + room.room_id);
rooms[req.body.roomName] = room.room_id;
});
});
};
exports.rooms = rooms;
If you are using Express.js, you can register in another place a route like this:
var roomsManager = require('./path/to/the/module');
//handle the create room endpoint
app.post('/room', roomsManager.create);
//get the room_id given a room name:
console.log('the room id of "some room" is:', roomsManager.rooms["some room"]);

Resources