I want to display User Verification menu only if user is not verified in node js
header.ejs
<% if(!isVerified(user.id)){%>
<li>User Verification</li>
<% } %>
function.js
module.exports.isVerified = function(user_id) {
return new Promise(function(resolve, reject) {
var sql = 'SELECT * FROM `users` WHERE id='+mysql.escape(user_id)+' and verified=1';
config.db.query(sql,function (err, rows){
if(err){
reject(false);
}else{
resolve(rows);
}
});
});
}
but it is not showing the menu....what should i do? I don't know i'm new in nodejs. Thanks in advance
Finally after a week i have solved this problem
function.js (same as i have posted in question)
module.exports.isVerified = function(user_id) {
return new Promise(function(resolve, reject) {
var sql = 'SELECT * FROM `users` WHERE id='+mysql.escape(user_id)+' and verified=1';
config.db.query(sql,function (err, rows){
if(err){
reject(false);
}else{
resolve(rows);
}
});
});
}
now the change that i have done here is in app.js and header.ejs file.
app.js
const fn = require('./helper/function_helper')
app.use(async function(req, res, next) {
if(req.session.user.id){
res.locals.user = await fn.isVerified (req.session.user.id);
//so now i can access user.verified in header.ejs file.
}
next();
});
header.ejs
//instead of using the isVerified() function I have used the user.verified
<%if(user.verified==0){%>
<li>User Verification</li>
<%}%>
Your promise doesn't return a boolean, it wait and indicate if the SQL query worked or not, you need to return a boolean in both case.
Since you are using a promise, you are dealing with asynchronous programming. What that means is that, your returns are unpredictable. How you should fix that is defining promise separately and check it with a code block similar to .then(function(res){...})
I recommend you to look at these resources:
Javascript Promises
How to return inside promise?
use a module for node that provide synchronous functions. Here you'll find a module that provide sync/async functions to deal with mysql:
node-mysql-libmysqlclient
//Sample code
module.exports.isVerified = function (user_id) {
var config = require("./config.json") ;
var mysql = require('mysql-libmysqlclient') ;
var client = mysql.createConnectionSync(config.host, config.user, config.password, config.database) ;
var flag = false;
var query = 'SELECT * FROM `users` WHERE id=' + mysql.escape(user_id) + ' and verified=1' ;
var handle = client.querySync(query) ;
var results = handle.fetchAllSync() ;
if (results.length > 0)
{
flag = true;
} else
{
flag = false;
}
console.log(JSON.stringify(results)) ;
return flag;
}
I don't know if this fix your problem, but your ejs code is wrong. You have not closed the ejs tags. This is the proper syntax
<% if(!isVerified(user.id)){ %>
<li>User Verification</li>
<% } %>
Related
I'm trying to get data from MongoDB collection and then save it to a global object.Later I need to parse it to HTML template.
Here is my code:
When user log onto his profile: then we need to get his projects and here we call findeprojects() function
usrRouter.route('/profile')
.all(function (req,res,next) {
if(!req.user){
res.redirect('/');
}
next();
})
.get(function (req,res,userObj) {
// var proj = findprojects();
userObj = req.user;
var pro = {};
pro = findprojects(userObj);
res.render('index',{name:userObj.username, email:userObj.email});
//res.sendFile('profile.html',{root:path.join(__dirname,'../public'),},{name:userObj.username});
});
Here is findeprojects function code:
var findprojects = function(obj) {
var usern = obj.username;
mongodb.connect(url,function(err, db){
if(err) throw err;
var collection = db.collection('projects');
//console.log(usern);
collection.find({'pusername':usern});
cursor =db.collection('projects').find({ 'pusername': usern }).toArray(function(err,items){
//console.log(items);
var i;
for(i=0; i<items.length;){
userProjects.createdBy = items[i].pusername;
userProjects.proName = items[i].projectName;
userProjects.proType = items[i].projectType;
userProjects.proDesc = items[i].projectDesc;
//return userProjects;
i = i+1;
}
});
console.log(userProjects);
});
};
I have declared global object at the top like:
userProjects = {
createdBy:'',
proName:'',
proType:'',
proDesc:''
};
But when I console userprojects object after calling the findeprojects() function it displays empty values.
why dont you use mongoose to model your stuff.
its more intuitive and you no need to declare the global object and do the mapping in the for loop that you are doing.
also your approach is a bit wrong in terms of when you iterate through for aren't you overwriting ?
say you have two documents where pusername is abdul.
so in your case you loose first object which will get overwritten by the second one.
i see that you commented out a return statement but even that wont work properly.
from a design point of view your approach is not efficient.
in mongoose you can do:
{
var userProjectSchema = new mongoose.Schema({
createdBy: { type: String }
, proName: String
, proType: String
, proDesc: String
});
// Find a single document by username.
userProjectSchema.findOne({ pusername : 'abdul' }, function(err, resDoc) {
if (err) return console.error(err);
// do your html stuff here
});
// Find all documents.
userProjectSchema.find(function(err, results) {
if (err) return console.error(err);
// do your html stuff here
});
}
Considering that my server.js looks almost like this. Just send you the relevant part. I did not receive anything from the query, I do have data in the database, and "sendNotification" is triggered by the jQuery function in the client. Everything works and since var notis = []; returns an empty value and is what is shows as response. I know I have to debug SQL and that's what I'm going to do but anyway want to be sure of this other things. So my questions are:
1) Is a right syntax for node.js, considering this async behavior? (which I still don't understand )
2) The query always should be inside of the "io.sockets.on('connection')" part?
connection = mysql.createConnection({
host: 'localhost',
user: '',
password: "",
database: 'table' //put your database name
}),
...
connection.connect(function(err) {
// connected! (unless `err` is set)
console.log(err);
});
…
var sqlquery = function(uID,vs){
var notis = [];
connection.query("SELECT * FROM notification WHERE kid = ? AND v = ? ORDER BY id DESC",[uID,vs])
.on("result", function (data){
return notis.push(data);
});
};
io.sockets.on('connection', function(socket) {
...
socket.on("sendNotification", function(data) {
var roomBName = data.room_name.replace("room-",""),
found = [];
var roomSelected = _.find(rooms, function (room) { return room.id == roomBName });
for (var person in people) {
for (var i = 0, numAttending = roomSelected.peopleAttending.length; i < numAttending; i++) {
if (people[person].name == roomSelected.peopleAttending[i]) {
found.push(person);
}
}
}
for (var i = 0, numFound = found.length; i < numFound; i++) {
**result = sqlquery(9,2);**
io.to(found[i]).emit('notification', result);
};
});
Your sqlquery() function will not accomplish anything useful. Because connection.query() is asynchronous, that means it provides the response sometime LATER after sqlquery() has already finished.
The only way in node.js to use an async result is to actually use it in the callback that provides it. You don't just stuff it into some other variable and expect the result to be there for you in other code. Instead, you use it inside that callback or you call some other function from the callback and pass it the data.
Here's one way, you could change your sqlquery() function:
var sqlquery = function(uID, vs, callback){
connection.query("SELECT * FROM notification WHERE kid = ? AND v = ? ORDER BY id DESC",[uID,vs])
.on("result", function (data){
callback(null, data);
});
// need to add error handling here if the query returns an error
// by calling callback(err)
};
Then, you could use the sqlquery function like this:
found.forEach(function(person, index) {
sqlquery(..., function(err, result) {
if (err) {
// handle an error here
} else {
io.to(person).emit('notification', result);
}
});
});
And, it looks like you probably have similar async issues in other places too like in connection.connect().
In addition to #jfriend00, this could be done with new ES6 feature Promise :
var sqlquery = function(uID, vs){
return new Promise(function(resolve, reject){
connection.query("SELECT * FROM notification WHERE kid = ? AND v = ? ORDER BY id DESC",[uID,vs])
.on("result", function (data){
resolve(data);
});
});
};
Now you can use it like :
found.forEach(function(person, index) {
sqlquery(...)
.then(function(result){
io.to(person).emit('notification', result);
});
});
In the code
var stuff_i_want = '';
stuff_i_want = get_info(parm);
And the function get_info:
get_info(data){
var sql = "SELECT a from b where info = data"
connection.query(sql, function(err, results){
if (err){
throw err;
}
console.log(results[0].objid); // good
stuff_i_want = results[0].objid; // Scope is larger than function
console.log(stuff_i_want); // Yep. Value assigned..
}
in the larger scope
stuff_i_want = null
What am i missing regarding returning mysql data and assigning it to a variable?
============ New code per Alex suggestion
var parent_id = '';
get_info(data, cb){
var sql = "SELECT a from b where info = data"
connection.query(sql, function(err, results){
if (err){
throw err;
}
return cb(results[0].objid); // Scope is larger than function
}
==== New Code in Use
get_data(parent_recording, function(result){
parent_id = result;
console.log("Parent ID: " + parent_id); // Data is delivered
});
However
console.log("Parent ID: " + parent_id);
In the scope outside the function parent_id is null
You're going to need to get your head around asynchronous calls and callbacks with javascript, this isn't C#, PHP, etc...
Here's an example using your code:
function get_info(data, callback){
var sql = "SELECT a from b where info = data";
connection.query(sql, function(err, results){
if (err){
throw err;
}
console.log(results[0].objid); // good
stuff_i_want = results[0].objid; // Scope is larger than function
return callback(results[0].objid);
})
}
//usage
var stuff_i_want = '';
get_info(parm, function(result){
stuff_i_want = result;
//rest of your code goes in here
});
When you call get_info this, in turn, calls connection.query, which takes a callback (that's what function(err, results) is
The scope is then passed to this callback, and so on.
Welcome to javascript callback hell...
It's easy when you get the hang of it, just takes a bit of getting used to, coming from something like C#
I guess what you really want to do here is returning a Promise object with the results. This way you can deal with the async operation of retrieving data from the DBMS: when you have the results, you make use of the Promise resolve function to somehow "return the value" / "resolve the promise".
Here's an example:
getEmployeeNames = function(){
return new Promise(function(resolve, reject){
connection.query(
"SELECT Name, Surname FROM Employee",
function(err, rows){
if(rows === undefined){
reject(new Error("Error rows is undefined"));
}else{
resolve(rows);
}
}
)}
)}
On the caller side, you use the then function to manage fulfillment, and the catch function to manage rejection.
Here's an example that makes use of the code above:
getEmployeeNames()
.then(function(results){
render(results)
})
.catch(function(err){
console.log("Promise rejection error: "+err);
})
At this point you can set up the view for your results (which are indeed returned as an array of objects):
render = function(results){ for (var i in results) console.log(results[i].Name) }
Edit
I'm adding a basic example on how to return HTML content with the results, which is a more typical scenario for Node. Just use the then function of the promise to set the HTTP response, and open your browser at http://localhost:3001
require('http').createServer( function(req, res){
if(req.method == 'GET'){
if(req.url == '/'){
res.setHeader('Content-type', 'text/html');
getEmployeeNames()
.then(function(results){
html = "<h2>"+results.length+" employees found</h2>"
html += "<ul>"
for (var i in results) html += "<li>" + results[i].Name + " " +results[i].Surname + "</li>";
html += "</ul>"
res.end(html);
})
.catch(function(err){
console.log("Promise rejection error: "+err);
res.end("<h1>ERROR</h1>")
})
}
}
}).listen(3001)
Five years later, I understand asynchronous operations much better.
Also with the new syntax of async/await in ES6 I refactored this particular piece of code:
const mysql = require('mysql2') // built-in promise functionality
const DB = process.env.DATABASE
const conn = mysql.createConnection(DB)
async function getInfo(data){
var sql = "SELECT a from b where info = data"
const results = await conn.promise().query(sql)
return results[0]
}
module.exports = {
getInfo
}
Then, where ever I need this data, I would wrap it in an async function, invoke getInfo(data) and use the results as needed.
This was a situation where I was inserting new records to a child table and needed the prent record key, based only on a name.
This was a good example of understanding the asynchronous nature of node.
I needed to wrap the all the code affecting the child records inside the call to find the parent record id.
I was approaching this from a sequential (PHP, JAVA) perspective, which was all wrong.
Easier if you send in a promise to be resolved
e.g
function get_info(data, promise){
var sql = "SELECT a from b where info = data";
connection.query(sql, function(err, results){
if (err){
throw err;
}
console.log(results[0].objid); // good
stuff_i_want = results[0].objid; // Scope is larger than function
promise.resolve(results[0].objid);
}
}
This way Node.js will stay fast because it's busy doing other things while your promise is waiting to be resolved
I've been working on this goal since few weeks, without any result, and I finally found a way to assign in a variable the result of any mysql query using await/async and promises.
You don't need to understand promises in order to use it, eh, I don't know how to use promises neither anyway
I'm doing it using a Model class for my database like this :
class DB {
constructor(db) {
this.db = db;
}
async getUsers() {
let query = "SELECT * FROM asimov_users";
return this.doQuery(query)
}
async getUserById(array) {
let query = "SELECT * FROM asimov_users WHERE id = ?";
return this.doQueryParams(query, array);
}
// CORE FUNCTIONS DON'T TOUCH
async doQuery(queryToDo) {
let pro = new Promise((resolve,reject) => {
let query = queryToDo;
this.db.query(query, function (err, result) {
if (err) throw err; // GESTION D'ERREURS
resolve(result);
});
})
return pro.then((val) => {
return val;
})
}
async doQueryParams(queryToDo, array) {
let pro = new Promise((resolve,reject) => {
let query = queryToDo;
this.db.query(query, array, function (err, result) {
if (err) throw err; // GESTION D'ERREURS
resolve(result);
});
})
return pro.then((val) => {
return val;
})
}
}
Then, you need to instantiate your class by passing in parameter to constructor the connection variable given by mysql. After this, all you need to do is calling one of your class methods with an await before. With this, you can chain queries without worrying of scopes.
Example :
connection.connect(function(err) {
if (err) throw err;
let DBModel = new DB(connection);
(async function() {
let oneUser = await DBModel.getUserById([1]);
let allUsers = await DBModel.getUsers();
res.render("index.ejs", {oneUser : oneUser, allUsers : allUsers});
})();
});
Notes :
if you need to do another query, you just have to write a new method in your class and calling it in your code with an await inside an async function, just copy/paste a method and modify it
there are two "core functions" in the class, doQuery and doQueryParams, the first one only takes a string as a parameter which basically is your mysql query. The second one is used for parameters in your query, it takes an array of values.
it's relevant to notice that the return value of your methods will always be an array of objects, it means that you'll have to do var[0] if you do a query which returns only one row. In case of multiple rows, just loop on it.
I'm a bit new in Node.JS and Express framework and I have a great problem with the code below:
app.get('/student', function(req, res) {
var dbRequest = 'SELECT * FROM Students WHERE IDCard = \'' + req.query['id'] + '\'';
db.all(dbRequest, function(error, rows) {
if(rows.length !== 0) {
/* Save data. */
}
else
res.render('incorrect_student'); /* Render the error page. */
});
dbRequest = 'SELECT * FROM Groups WHERE Name = \'' + req.query['group'] + '\'';
db.all(dbRequest, function(error, rows) {
/* Add selected data to previous saved data. */
}
});
res.render('student', {data: /* data from both queries above */});
});
As I have written in comment blocks, I would like to: execute first select query, save data from rows object, execute second query, again save received data in other object and then finally render the page passing data from both queries. My question is, what is the best way to do that?
I know that there is a problem caused by anonymous function. I have tried to fix the problem for over five hours as follows:
Clone rows object to another in anonymous function and then pass it to res.render. This solution dosen't work, because values of copied object are not visible (undefined) outside this function - only inside it.
Render the student page twice - it was really naive of course.
Change db.all command to db.prepare and then db.run - it wasn't working too.
Return object by the anonymous function and then assign it to external object defined between app.get and var dbRequest. The result was as described in 1st point.
I have also an idea to create "subpages" containig parts of student page, which need variables from only one query. The other idea is to use some other functions of db, req, res or app objects. But, as I said before, I'm new in Express and I don't know how to realize my above ideas.
Please note that it is impossible to join tables - in fact, I want to make 4-5 queries and then render my view. I'm using SQLite3 database.
Thank you very much for your help! I hope that you'll help me to solve my problem.
In your situation, I would split up the database calls into separate calls, and make use of the next middleware function.
It would looks something like:
function findStudent(req, res, next) {
var dbRequest = 'SELECT * FROM Students WHERE IDCard = \'' + req.query['id'] + '\'';
db.all(dbRequest, function(error, rows) {
if(rows.length !== 0) {
req.students = rows;
return next();
}
res.render('incorrect_student'); /* Render the error page. */
});
}
function findGroups(req, res, next) {
dbRequest = 'SELECT * FROM Groups WHERE Name = \'' + req.query['group'] + '\'';
db.all(dbRequest, function(error, rows) {
/* Add selected data to previous saved data. */
req.groups = rows;
next();
}
});
}
function renderStudentsPage(req, res) {
res.render('student', {
students: req.students,
groups: req.groups
});
}
app.get('/student', findStudent, findGroups, renderStudentsPage);
When you GET /student, you first call findStudent. Once the db call is finished, it will either render an error page, or call next(). Calling next goes to the next function, findGroups, which will then call renderStudentsPage. You can store the data on the req object as you move down the line of functions.
Hope this helps, and here is more info:
http://expressjs.com/guide/using-middleware.html
edit/note:
I did not mention it earlier, but if you pass in an argument when calling next(), you will trigger the error handling state. Convention dictates next() is left parameter-less unless you have met an error instance.
You want to separate out the UI rendering aspect from the database call, so going further, your code could look like:
function findStudent(req, res, next) {
var dbRequest = 'SELECT * FROM Students WHERE IDCard = \'' + req.query['id'] + '\'';
db.all(dbRequest, function(error, rows) {
if (error || !rows.length) {
return next(error);
}
req.students = rows;
return next();
});
}
And then elsewhere in your code you can handle rendering error pages.
I know this is an old question, but for anybody still having problems and using MongoDB instead this is what worked for me.
//index.js
const express = require('express');
const router = express.Router();
function getData (req, res, next) {
var db = req.db;
var collection = db.get('usercollection');
collection.find({}, {}, function(e, docs) {
req.data = docs;
return next();
});
}
function getVendor (req, res, next) {
var db = req.db;
var collection = db.get('usercollection');
collection.distinct("vendor", function(e, docs) {
req.vendor = docs
next();
});
}
function getType (req, res, next) {
var db = req.db;
var collection = db.get('usercollection');
collection.distinct("type", function(e, docs) {
req.type = docs
next();
});
}
function renderData(req, res) {
res.render('index', {
data: req.data,
vendor: req.vendor,
type: req.type
});
}
/* GET home page. */
router.get('/', getData, getVendor, getType, renderData);
module.exports = router;
Then inside your ejs file
//index.ejs
<body>
<div id="app">
<h1>Choose a Vendor</h1>
<template v-for="vendor in values.vendor">
<label :for="vendor">{{ vendor }}</label>
<input type="radio" :value="vendor" v-model="flagpole.vendor">
</template>
<div>
<template v-for="type in values.type">
<label :for="type">{{ type }}</label>
<input type="radio" :value="type" v-model="flagpole.type">
</template>
</div>
</div>
<script type="text/javascript">
var vendor = <%- JSON.stringify(vendor) %>
var type = <%- JSON.stringify(type) %>
var vm = new Vue({
el: '#app',
data: {
values: {
vendor: vendor,
type: type
},
flagpole: {
vendor: '',
type: ''
}
},
I have the following code to insert data into DB - this code has to be executed in a sequential order
Router JS
module.exports = function(app) {
app.get('/registerUser', function(req, res ) {
objuser.userName = 'testuser';
objuser.password = 'password';
objuser.status = true;
registerUser (objuser ); //calls Business.js
res.OK();
res.end ();
});
}
Business.js
var registerUser = function (objuser )
{
userDB.registerUser (objuser ) ; //calls db.js
};
db.js
exports.registerUser = function (objUser )
{
var User = db.model(strCollectionName, UserSchema );
var objSchema = new User(objUser);
objSchema.save(function (err)
{
if (err)
console.error (err);
else
console.log ("registerUser : Data insertion success.");
});
}
In the db.js Im getting error from Mongo if I try to insert duplicate value. I wan to pass the error message to HTML page to display the same. What should I do? I tried
throw Error (err)
But it breaks the server.
Assuming you are using expressjs, I'd make use of the next callback. like so:
app.get('/registerUser', function (req, res, next) {
objuser.userName = 'testuser';
objuser.password = 'password';
objuser.status = true;
registerUser(objuser, function (err) {
if(err) {
//this will be handled by express's errorHandler or whatever you have configured
return next(err);
}
//do whatever you want to do with the response
});
});
If you don't want to make your Business.js call async then you will obviously change this code to a try...catch flow. Node.js apps are happier using async calls though, so a common convention in nodejs apps is to expose a callback using the (err, result) parameters. So your db.js call would be :
exports.registerUser = function (objUser, callback )
{
var User = db.model(strCollectionName, UserSchema );
var objSchema = new User(objUser);
objSchema.save(function (err) {
if (err) return callback(err);
return callback(null, objSchema);
});
}
By now you probably notice that your Business.js call would just be a mediator between your route and your db code...whether you need it or not is up to you.
HTH,
Mike
If you are using node.js >= 0.8.x you can use connect-domain middleware that adds new domain functionality to your express/connect application. With doamin module you don't need to pass error up manually. You can simple throw error and it will be passed to error handler automatically.