I am trying to pass some data from my db to the router which then passes the data to the view.
My model code :
var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'test'
});
var result; // empty var which should later be filled with the querys result
connection.connect();
var query = connection.query('SELECT * FROM users', function(err, res, fields) {
if (err) throw err;
result = res; // overwrite result with the querys result
console.log(res); // This prints out everything I need
});
module.exports = {
data: result // should contain the query result (= 2 objects in this case)
}
Now to my route file :
var express = require('express');
var router = express.Router();
var Users = require('../models/users');
console.log(Users.data);
/* GET home page. */
router.get('/users', function(req, res) {
res.render('api', { data: Users.data, title: "Test API Output" });
});
module.exports = router;
When I console.log Users or Users.data I get undefined. I don't really get why this is the case. How else am I supposed to pass data along the files.
All help is gladly read :) Thank you.
I am trying to pass some data from my db to the router which then passes the data to the view.
My model code :
var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'test'
});
var result; // empty var which should later be filled with the querys result
connection.connect();
var query = connection.query('SELECT * FROM users', function(err, res, fields) {
if (err) throw err;
result = res; // overwrite result with the querys result
console.log(res); // This prints out everything I need
});
module.exports = {
data: result // should contain the query result (= 2 objects in this case)
}
Now to my route file :
var express = require('express');
var router = express.Router();
var Users = require('../models/users');
console.log(Users.data);
/* GET home page. */
router.get('/users', function(req, res) {
res.render('api', { data: Users.data, title: "Test API Output" });
});
module.exports = router;
When I console.log Users or Users.data I get undefined. I don't really get why this is the case. How else am I supposed to pass data along the files.
All help is gladly read :) Thank you.
Share Improve this question asked Oct 7, 2015 at 19:16 noa-devnoa-dev 3,6419 gold badges36 silver badges73 bronze badges3 Answers
Reset to default 5module.exports
are being evaluated the second you require
and variables are not passed by reference in this case.
What that means for your code is the following:
var result; // result is "undefined" because it does not contain a value here
// You are doing your DB queries here...
module.exports = {
data: result // ...and because the query has not finished here yet, result
// is still undefined.
// This is also a good example of a so called "race condition", because there is a
// slight (improbable) chance that the query might have already finished.
// Hence, it could happen that sometimes result is already filled.
}
When you now require
the above file in another file of your code, the above is being evaluated and saved straight away (result is undefined at that point in time, hence it is also undefined when it exports).
Your query is being executed and written into the result
variable, but at that point in time you can not modify the exported variable anymore – because it is it's own variable and not merely a reference to result
).
What you could do is the following:
function getData(callback) {
connection.query('SELECT * FROM users', function(err, res, fields) {
callback(err, res);
});
}
module.exports = {
getData: getData
}
and then in your other file:
var Users = require('../models/users');
Users.getData(function(err, result) {
// TODO: Error handling.
console.log(result);
});
That's exactly why it's so easy with JavaScript to end up in callback hell, because of it's asynchronous nature.
The above is the exact same situation as if you, f.e., want to get some data via AJAX from a server and then fill tables with it. When you start creating the table before you have the data (so the AJAX request is not yet plete), you end up with an empty table. What could do is:
- you create a variable that holds your data and
- a function that creates the table
when you then ask the server for the data (via AJAX) you wait until you get the data (pletion callback) and only then you start creating the table: filling your variable and calling the function to fill the table with the data.
Server-Side JavaScript is the same as client-side. Never forget this.
As a little homework for the reader: the way to get out of callback hell is by reading up on promises – a pattern/architecture which reduces indents and saves lots of headaches :)
(update: Lucas' answer is basically telling the same thing as I did)
(update 2: wrong way of handling err
)
I suggest realize the consult in the route file, some like this:
var express = require('express');
var router = express.Router();
var Users = require('../models/users');
var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'test'
});
var result; // empty var which should later be filled with the querys result
connection.connect();
/* GET home page. */
router.get('/users', function(req, res) {
var query = connection.query('SELECT * FROM users', function(err, res, fields) {
if (err) throw err;
result = res; // overwrite result with the querys result
res.render('api', { data: res.data, title: "Test API Output" });
});
});
module.exports = router;
But you can configure the connection with database in another file, in libs/mysql_connect.js
.
The undefined
is caused because the response
of connection.query
don't works out of the connection.query
.
If you really want the query to run only once and then just re-use the already queried data, I think you are after something like this for your model:
...
var data;
var mymodel = {};
...
mymodel.getData = function(callback) {
if(data) {
callback(data);
} else {
db.query('select * from users', function(err,res,fields) {
// error checking and such
data = res;
callback(data);
});
}
}
module.exports = mymodel
In your router, you'd then use it like this:
...
router.get('/users', function(req, res) {
Users.getData(function(mydata) {
res.render('api', { data: mydata, title: "Test API Output" });
});
});
The first time you call getData, you'll get a fresh result, and on subsequent calls you get the cached result.
While you could expose data in mymodel directly, and only use the callback in case it is still undefined, that'd make your code in the router more convulated.