This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
router.post('/loginv', function (req,res) {
var id = req.body.id;
var pass = req.body.pass;
if(login.login(id,pass)=='validated'){
res.sendfile('views/welcome.html');
}else{
res.send('dont give up');
}
var result = login.login(id,pass);
console.log(result);
});
module.exports={
login : function(id,pass){
var q = "SELECT * FROM user where id = ? and pass = ?";
var ret = 'default';
DB.DB.query(q, [id,pass], function (error,result) {
if(error){
console.log('not found');
ret = 'unrecognized';
} else{
console.log('found');
ret = 'validated';
}
});
return ret;
}};
console.log :
GET /login 304 4.028 ms - -
default
POST /loginv 200 40.558 ms - 12
found
found
as you can see the value ret returned from the following code is not being changed although it follows the procedure of the function properly..
i'm new to node js and js stuff so any comments and advice will definitely be helpful thx :)
DB.query() is async, so login function do not wait the execution of the code before returning ret. You need to add a callback to the login method (or use a promise).
A working code:
module.exports = {
login : function(id,pass,cb){
var q = "SELECT * FROM user where id = ? and pass = ?";
DB.DB.query(q, [id,pass], function (error,result) {
if(error){
console.log('not found');
cb(error, 'unrecognized');
} else{
console.log('found');
cb(null, 'validated');
}
});
}
};
The other file:
router.post('/loginv', function (req,res) {
var id = req.body.id;
var pass = req.body.pass;
login.login(id,pass, function(err, result) {
if (err) {
console.log(err);
res.send('dont give up');
return;
}
if (result === 'validated') {
res.sendfile('views/welcome.html');
}else{
console.log('Unknown error');
}
})
});
I suggest you to read links posted here and this question which can gives you an idea about callbacks and promises.
PS: I do not know which library you are using for DB, but you MUST sanitize input before doing queries, if the library does not do it for you
Related
I'am setting up a login page for my app. I want to send a file after verifing if the login page is provided with proper username and password.
I have a handler for a post request which checks if the user entered correct username and password.
app.post('/login',function(req,res){
var data="";
var flag_isthere=0,wrongpass=0;
console.log('login-done');
req.setEncoding('UTF-8')
req.on('data',function(chunk){
data+=chunk;
});
req.on('end',function()
{
MongoClient.connect("mongodb://localhost:27017/userdetails",{useNewUrlParser: true ,useUnifiedTopology: true },function(err,db)
{
if(err) throw err;
var q = JSON.parse(data)
const mydb=db.db('userdetails')
var c=mydb.collection('signup').find().toArray(
function(err,res)
{
for(var i=0;i<res.length;i++)
if( (res[i].email==q['email']) ) //check if the account exists
{
flag_isthere=1;
if( (res[i].pass != q['pass'] ) )
wrongpass=1;
break;
}
if(flag_isthere==0)
{
console.log(q['email'], ' is not registered')
}
else
{
console.log('Already exists!!!');
}
if( wrongpass==1)
{
console.log('password entered is wrong')
}
if(flag_isthere==1 && wrongpass==0)
{
console.log('Congratulations,username and password is correct');
res.send( { login:'OK', error:'' } ); //this statement is giving an error in node JS part
}
});//var c
})//mongoclient.connect
})//req.on
res.send({ login:'OK', error:'' }); //this works properly in node JS
console.log(flag_isthere , wrongpass ) //but here the flag_isthere==0 and wrongpass==0 , so it won't get validated
});
It gives the error as
TypeError: res.send is not a function
at E:\ITT_project_shiva\loginserver_new.js:112:25
at result (E:\ITT_project_shiva\node_modules\mongodb\lib\operations\execute_operation.js:75:17)
at executeCallback (E:\ITT_project_shiva\node_modules\mongodb\lib\operations\execute_operation.js:68:9)
at handleCallback (E:\ITT_project_shiva\node_modules\mongodb\lib\utils.js:129:55)
at cursor.close (E:\ITT_project_shiva\node_modules\mongodb\lib\operations\to_array.js:36:13)
at handleCallback (E:\ITT_project_shiva\node_modules\mongodb\lib\utils.js:129:55)
at completeClose (E:\ITT_project_shiva\node_modules\mongodb\lib\cursor.js:859:16)
at Cursor.close (E:\ITT_project_shiva\node_modules\mongodb\lib\cursor.js:878:12)
at cursor._next (E:\ITT_project_shiva\node_modules\mongodb\lib\operations\to_array.js:35:25)
at handleCallback (E:\ITT_project_shiva\node_modules\mongodb\lib\core\cursor.js:32:5)
[nodemon] app crashed - waiting for file changes before starting...
How do I send the response to the user after proper validation?
It's not that you're doing it from the callback that's the problem. There are two different problems:
You're shadowing res by redefining it in the callback's parameter list
(Once you fix that) You're calling res.send twice:
Once at the end of your posthandler
Once within the callback
send implicitly completes the response, so you can only call it once.
In your case, you want to call it from within your callback, once you've determined that none of the records matches.
See *** comments for a rough guideline (but keep reading):
app.post('/login', function(req, res) {
var data = "";
var flag_isthere = 0,
wrongpass = 0;
console.log('login-done');
req.setEncoding('UTF-8')
req.on('data', function(chunk) {
data += chunk;
});
req.on('end', function() {
MongoClient.connect("mongodb://localhost:27017/userdetails", {
useNewUrlParser: true,
useUnifiedTopology: true
}, function(err, db) {
if (err) throw err;
var q = JSON.parse(data)
const mydb = db.db('userdetails')
var c = mydb.collection('signup').find().toArray(
function(err, array) { // *** Renamed `res` to `array
for (var i = 0; i < array.length; i++)
if ((array[i].email == q['email'])) //check if the account exists
{
flag_isthere = 1;
if ((array[i].pass != q['pass']))
wrongpass = 1;
break;
}
if (flag_isthere == 0) {
console.log(q['email'], ' is not registered')
} else {
console.log('Already exists!!!');
}
// *** Handle result here
if (flag_isthere == 1 && wrongpass == 0) {
console.log('Congratulations,username and password is correct');
res.send({ login: 'OK', error: '' }); //this statement is giving an error in node JS part
} else if (wrongpass == 1) {
console.log('password entered is wrong')
// *** res.send(/*...*/)
} else {
// Handle the issue that there was no match
// *** res.send(/*...*/)
}
}
); //var c
}) //mongoclient.connect
}) //req.on
// *** Don't try to send a response here, you don't know the answer yet
});
but, it seems like you should be able to find just the one user (via findOne? I don't do MongoDB), rather than finding all of them and then looping through the resulting array.
See also the answers to these two questions, which may help you with asynchronous code issues:
How do I return the response from an asynchronous call?
Why is my variable unaltered after I modify it inside of a function?
A couple of other notes:
I strongly recommend using booleans for flags, not numbers.
NEVER store actual passwords in your database!! Store a strong hash, and then compare hashes.
You might find async/await syntax more convenient to work with. I think recent MongoDB clients support promises (which you need for async/await).
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
why wont usernametoid function return anything? i know it exist by consoling it out, but it wont store in the otherplayerid variable? why?
my app: ( calling post api kill)
var userFunc = require('../factory/user_factory.js');
app.post('/api/kill', function (req, res) {
var username = "signature";//req.query.username;
var otherplayerid = userFunc.usernametoid(username);
if (!(otherplayerid)) {
console.log("other player is acually " + otherplayerid);
result.push("denne brukeren finnes ikke! " + otherplayerid);
} else {
}
});
and my user_factory:
var articles = require('../controllers/articles.server.controller'),
path = require('path'),
mongoose = require('mongoose'),
Article = mongoose.model('Article'),
Users = mongoose.model('User'),
errorHandler = require(path.resolve('./modules/core/server/controllers/errors.server.controller'));
exports.usernametoid = usernametoid;
function usernametoid(id) {
var query = Users.findOne( { username : id } );
query.exec(function(err, datas) {
console.log(datas._id);
return datas._id;
});
}
console:
other player is acually undefined
57c1c0f3b6b20c011242bf22
You need to read about asynchronous calls. Which is db request. Simple fix is callback:
function something(data, callback) {
return callback('some data from db')
}
something('x', function(cb) {
console.log(cb)
}
it is good practise to return two values (error, callback). But you can read it later on.
There are also promises. You can read about them insted of callbacks, but it is recommended to know both.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
I have declared class which generates the records and simply return it but it is returning undefined.
var classObj = new User();
var user = classObj.generateUserResponse(val1,mode);
console.log(user) //undefined
User.prototype.generateUserResponse = function (userid, mode) {
conn.query('select * from users where user_id = ?', [userid], function (err, user) {
if(mode == 'true') {
var genObj = new CustomerJSON();
userObj = genObj.generateUserCustomer(user);
console.log(userObj) // displays the value
return userObj;
} else {
// do something else
}
})
What I am doing above is creating a new class and passing a user object in a new class for further processing. I can console log and can see the data but when I return userObj it displays undefine.
It is right, because the invoked asynchronous function calls the callback (which returns the object to noone) after you log the object to console.
The function generateUserResponse returns no value.
Solution: make the required actions in the callback function.
Pavel is correct. Your function is asynchronous. You need a callback. Try something like this:
var classObj = new User();
classObj.generateUserResponse(val1, mode, function(userObj) {
console.log(userObj);
});
User.prototype.generateUserResponse = function(userid, mode, callback) {
//you could decide to return conn.query here and handle it differently above
conn.query('select * from users where user_id = ?', [userid], function(err, user) {
if (mode == 'true') {
var genObj = new CustomerJSON();
userObj = genObj.generateUserCustomer(user);
console.log(userObj) // displays the value
return callback(userObj);
} else {
// do something else
//THEN
return callback(userObj);
}
})
});
Or you could return conn.query(... and handle the promise it returns based on whatever library you're using.
I am trying to check to see if a document is already in the database before posting. I am posting via a jQuery.post() method to my endpoint which is api/songs.
What I want to check is to see if the song is already in the database. I can check that by querying the songId parameter that I am pushing to the database. If the song is already in the database I want to increment a number by 1.
What I have been trying to do is use mongo's findOne(), but I can't get it to work in the POST. My post route looks like this:
router.post('/api/songs', function(req, res){
if(Song.findOne({songId: req.body.songId}).length > -1){
console.log('already in there fam')
} else{
var song = new Song();
song.artistName = req.body.artistName;
song.titleName = req.body.titleName;
song.songId = req.body.songId;
song.songImg = req.body.songImg;
song.save(function(err) {
if (err) {
console.log("Error: " + err)
} else {
console.log("created fam")
}
})
};
console.log(song);
return res.json({message: "SongCreated"})
})
My problem is that I can't figure out what the findOne is returning. I want it to return a boolean so i've tried count() and length() but can't get it to return true. The req posts to the DB no matter what.
Any ideas?
All i/o operations in node.js are asynchronous. Your Song.findOne operation is asynchronous as well. You should wait for it to complete via callback functionality and then check the result of it.
Mongoose findOne method returns a promise. You can read more info about it here.
Example of promise execution:
var query = Song.findOne({songId: req.body.songId})
query.exec(function(err, song) {
})
Try the following code:
router.post('/api/songs', function(req, res){
Song.findOne({songId: req.body.songId}, function(err, song){
if (err) {
return console.log("Error: " + err)
}
if(song){
return console.log('already in there fam')
}
var song = new Song();
song.artistName = req.body.artistName;
song.titleName = req.body.titleName;
song.songId = req.body.songId;
song.songImg = req.body.songImg;
song.save(function(err) {
if (err) {
console.log("Error: " + err)
} else {
console.log("created fam")
}
})
console.log(song);
return res.json({message: "SongCreated"})
})
})
This question already has an answer here:
How to return value from Node.js function which contains DB query [duplicate]
(1 answer)
Closed 8 years ago.
I have a function inside of which there is a nested callback function structure. I want that first "mother" function to return a certain value, after it's been calculated in the callback functions sequence. However. it doesn't really work. Here's a simplified version of the code, do you think you could help?
console.log(finalResult());
function finalResult() {
var finalanswer = firstFunction(secondFunction);
function firstFunction (callback) {
var notion = 1;
callback(null, notion);
}
function secondFunction (err, notion) {
if (err) console.log(err);
var answer = notion + 1
return answer;
}
return finalanswer;
}
Thank you!
**UPDATE - THE ORIGINAL CODE**
return getContexts(makeQuery);
function getContexts (callback) {
dbneo.cypherQuery(context_query, function(err, cypherAnswer){
if(err) {
err.type = 'neo4j';
return callback(err);
}
// No error? Pass the contexts to makeQuery function
return callback(null,cypherAnswer);
});
}
function makeQuery (err,answer) {
// Error? Display it.
if (err) console.log(err);
// Define where we store the new contexts
var newcontexts = [];
// This is an array to check if there are any contexts that were not in DB
var check = [];
// Go through all the contexts we received from DB and create the newcontexts variable from them
for (var i=0;i<answer.data.length;i++) {
newcontexts.push({
uid: answer.data[i].uid,
name: answer.data[i].name
});
check.push(answer.data[i].name);
}
// Now let's check if there are any contexts that were not in the DB, we add them with a unique ID
contexts.forEach(function(element){
if (check.indexOf(element) < 0) {
newcontexts.push({
uid: uuid.v1(),
name: element
});
}
});
return newcontexts;
}
You're setting finalanswer equal to the return of firstFunction however, if you look at the body of firstFunction, it does not return anything. The last line of firstFunction should be:
return callback(null, notion);
I quickly tested this in the Chrome console and it seems to work as expected and logs 2 to the console.
UPDATE
Now that the original code has been posted I would update the code as such:
// call getContexts with a callback when complete
getContexts(function(err, contexts){
console.log(err);
console.log(contexts);
});
function getContexts (callback) {
dbneo.cypherQuery(context_query, function(err, cypherAnswer){
if(err) {
err.type = 'neo4j';
return callback(err);
}
// No error? Pass the contexts to makeQuery function
var contexts = makeQuery(null,cypherAnswer);
// we have our answer, call the callback
callback(null, contexts);
});
}
function makeQuery (err,answer) {
// Error? Display it.
if (err) console.log(err);
// Define where we store the new contexts
var newcontexts = [];
// This is an array to check if there are any contexts that were not in DB
var check = [];
// Go through all the contexts we received from DB and create the newcontexts variable from them
for (var i=0;i<answer.data.length;i++) {
newcontexts.push({
uid: answer.data[i].uid,
name: answer.data[i].name
});
check.push(answer.data[i].name);
}
// Now let's check if there are any contexts that were not in the DB, we add them with a unique ID
contexts.forEach(function(element){
if (check.indexOf(element) < 0) {
newcontexts.push({
uid: uuid.v1(),
name: element
});
}
});
return newcontexts;
}