I have been on this for a good few hours.
I have the below function which reads from a table in my postgres db. It works as expected if there is stored strings in a column.
I can't get the 'else if' statement to work when there is no string in a field. To test this out I have a completely empty column under brand_code and its still executing the 'else' statement.
Now, I know why. There are 3 rows in the table. When I change the else if to === 3, it works as I'd like.
What code do I need to make the 'else if' statement work if the field is empty? (I plan to expand the SELECT statement later).
readCodes: function(callback) {
var pool = new pg.Pool(config.PG_CONFIG);
pool.connect(function(err, client, done) {
if (err) {
return console.error('Error acquiring client', err.stack);
}
client
.query(
'SELECT brand_code FROM public.voucher_codes',
function(err, result) {
if (err) {
console.log(err);
callback('');
} else if (result.rows.length === 0 ) {
console.log(result);
callback('');
} else {
let codes = [];
for (let i = 0; i < result.rows.length; i++) {
codes.push(result.rows[i]['brand_code']);
}
callback(codes);
};
});
});
}
}
Really struggled with this all day so any help is appreciated.
I am still learning. Prior to last week, I have never coded so apologies if this is amateur hour.
The problem here is that you are checking if it has returned rows or not, what you need instead is to check in each row if the field is empty
I suggest using underscore for iterating over each row:
_.each(result.rows,function(element, index){
if(element['brand_code'].length != 0){
codes.push(element['brand_code'])
}else{
console.log('empty field # results['+index+']')
}
})
CODE :
readCodes: function(callback) {
var pool = new pg.Pool(config.PG_CONFIG);
pool.connect(function(err, client, done) {
if(err){return console.error('Error acquiring client',err.stack);}
client.query(
'SELECT brand_code FROM public.voucher_codes',
function(err, result) {
if (err){console.log('[!] Error:',err); callback('');}
else if(result.rows.length == 0 ){
console.log('[!] Error:','No rows returned!');
callback('');
} else {
let codes = [];
_.each(result.rows,function(element, index){
console.log(element , index)
if(element['brand_code'].length != 0){
codes.push(element['brand_code'])
}else{
console.log('empty field # results['+index+']')
}
})
callback(codes);
}
});
});
}
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).
I'm trying to check if an element exist before inserting it in my bdd.
I have to do this in order to (in the future) modify this existing element.
I'm using PouchDb and PouchDb-find with Node 6.9.1.
Actually I'm doing this:
for(var i = 0; i < 10;i++ ){
(function(_count, _pdb){
var count = _count;
var db = _pdb;
db.find({
selector: {numeroCandidat: parseInt(results[count].no_apb)}
}).then((result) => {
if(result.docs.length != 0){
console.log("l'étudiant existe");
}else{
console.log("l'étudiant n'existe pas");
var etudiant = {
"numeroCandidat": results[count].no_apb,
"nom": results[count].nom,
"numeroGroupe": "gr" + results[count].groupe,
"filiere": results[count].libelle,
};
db.post(etudiant).then((response) =>{
// handle response
console.log("STUDENT CREATED");
}).catch(function (err) {
console.log(err);
});
}
}).catch(function (err) {
});
})(i, this.pdb);
};
But the problem is : Due to the asynchronous version of my select query... if an element exists two times it appends that the second select occurred BEFORE the insertion of the first element, and I have this element two times in my database. I don't know how to deal with this one.
SO.. I'v found a workaround !
Simply create a function that I call recursivly after writting into my database.
Goodbye for loop.
var createStudents = function(_count, _pdb, _students){
if(_count >= 10) return;
console.log(_count);
var count = _count;
var db = _pdb;
var students = _students.slice(0);
db.find({
selector: {numeroCandidat: parseInt(students[count].no_apb)}
}).then((result) => {
if(result.docs.length != 0){
console.log("l'étudiant existe");
createStudents(++count,db,results);
}else{
var etudiant = {
"numeroCandidat": students[count].no_apb,
"nom": students[count].nom,
"numeroGroupe": "gr" + students[count].groupe,
"filiere": students[count].libelle,
"etudiantComms": [
{"commentaire": students[count].commentaire}
]
};
db.post(etudiant).then((response) =>{
// handle response
console.log("STUDENT CREATED");
createStudents(++count,db,results);
}).catch(function (err) {
console.log(err);
});
}
}).catch(function (err) {
});
}
createStudents(0,this.pdb,results);
How would you stop the rest of the code from executing in NodeJs (not termine the application with process.exit() just say this is the last line to be executed).
In regular javascript you have exit(), but that doesnt seem to work in nodejs.
Below is the situation:
connection.query(sql, [req.session.sessionUserPackagePassword] , function(err, rows, fields) {
if (!err) {
var userFound = false;
for(var i=0; i< rows.length; i++) {
// Make the comparaison case insensitive
if ((rows[i].deliveredToUser).toLowerCase() == `no`) {
userFound = true;
console.log(userFound);
[...]
}
}
if (!userFound) {
res.render('pickup/errorAlreadyDelivered', {});
// exit here
}
console.log(userFound);
// If the query fails to execute
} else {
console.log('Error while performing Query.');
res.render('errorConnection', {});
}
});
connection.end();
// Update the query to say the box has been delivered to user and specify time
// Establish the connection
[...]
res.render('pickup/openPackageClose', {
title: '',
helpButtonURL: '/help/help-dropPackage',
helpButtonTitle: 'Help'
});
});
Essentially when this condition is met, I would like the rest of the code not to be executed
if (!userFound) {
res.render('pickup/errorAlreadyDelivered', {});
// exit here
}
connection.end(); then return; seems like it might work for you.
So based on your comment on my other answer, it sounds like your program structure isn't what I thought it was. This should work:
connection.query(sql, [req.session.sessionUserPackagePassword] , function(err, rows, fields) {
if (!err) {
var userFound = false;
for(var i=0; i< rows.length; i++) {
// Make the comparaison case insensitive
if ((rows[i].deliveredToUser).toLowerCase() == `no`) {
userFound = true;
console.log(userFound);
[...]
}
}
if (!userFound) {
res.render('pickup/errorAlreadyDelivered', {});
connection.end();
} else {
console.log(userFound);
console.log('Error while performing Query.');
res.render('errorConnection', {});
connection.end();
}
I am writing a small Node js application for automatic vehicle location system.
Here is the code for where I am getting trouble.
markerData contains 4 rows but only in the log I can see the last row.
for (var i = 0, len = markerData.length; i < len; i++) {
var thisMarker = markerData[i];
sql.connect(config, function (err) {
var request = new sql.Request();
request.input('myval', sql.Int, thisMarker.id);
request.query('SELECT d.id, d.name, d.lastupdate, p.latitude, p.longitude, p.speed, p.course FROM dbo.devices AS d INNER JOIN dbo.positions AS p ON d.positionid = p.id AND d.id = p.deviceid WHERE (d.id = #myval)', function (err, recordset2) {
if (typeof recordset2 != 'undefined') {
thisMarker.position.lat = recordset2[0].latitude;
thisMarker.position.long = recordset2[0].longitude;
console.log(recordset2[0].id);
}
});
});
}
Please help me to solve the issue.
As var is not a block level variable in terms of scope, when `sql' module takes time to connect to the database asynchronously, the synchronous loop may change the value of the variable that's why you have the last row printed since the variable holds the reference to the last object at the time of successful connection.
Instead of _.each, I would recommend to use async module with async.each since you have few asynchronous operation to get rid of a synchronous loop.
You can check for samples here,
http://justinklemm.com/node-js-async-tutorial/
Here is your updated code with async.each
-> Install async module with npm install async --save
-> Then add the below reference in the required place,
// Reference
var async = require('async');
-> Modified code:
sql.connect(config, function (err) {
if(err) {
console.log('Connection error: ');
console.log(err);
} else {
async.each(markerData, function(thisMarker, callback) {
var request = new sql.Request();
request.input('myval', sql.Int, thisMarker.id);
request.query('SELECT d.id, d.name, d.lastupdate, p.latitude, p.longitude, p.speed, p.course FROM dbo.devices AS d INNER JOIN dbo.positions AS p ON d.positionid = p.id AND d.id = p.deviceid WHERE (d.id = #myval)', function (err, recordset2) {
if(err) {
console.log(err);
callback();
} else {
if (typeof recordset2 != 'undefined') {
thisMarker.position.lat = recordset2[0].latitude;
thisMarker.position.long = recordset2[0].longitude;
console.log(recordset2[0].id);
} else {
console.log('Recordset empty for id: ' + thisMarker.id);
}
callback();
}
});
}, function(err){
if(err) {
console.log(err);
}
});
}
});
I'm not entirely sure how your library works, but presumably recordset2 is an array of records. recordset2[0] is therefore the first record. If you want the next one you should probably try recordset2[1] and so on and so forth.
Arrays: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
You'll probably need to loop through all the elements in the array at some point. use a for loop for that:
for (var i = 0; i < recordset2.length; i++ {
console.log(recordset2[i])
}
That will print out everything your query returns.
I am using Mongodb and the findOne feature:
User.findOne({$or: [{email: req.body.email}, {mobile: req.body.mobile}]}
However the issue I am facing is with req.body.email and req.body.mobile - in certain cases can be empty.
I have initially solved this using:
var toSearchSmartString = {$or: [{email: req.body.email}, {mobile: req.body.mobile}]};
if (req.body.email.length == 0) {
toSearchSmartString = {mobile: req.body.mobile};
} else if (req.body.mobile.length == 0) {
toSearchSmartString = {email: req.body.email};
}
then in the findOne, simply using:
User.findOne(toSearchSmartString);
So I want to check is this 'safe' todo? The reason I ask is this safe is because if I don't set the default value for toSearchSmartString and instead set it at the end of the if block (in a else) I get 'undefined' for the string.
I'm concerned that the findOne method may use the default toSearchSmartString before the if else condition has been checked? Am I right to concerned about this?
Alternatively is there some Mongodb function I can use to solve?
UPDATE:
So after comments in answer below - having issues with the code:
I solved it by moving the var declaration above to where its used.
var contWithRegCallback = function(err, user) {
console.log(user);
}
if (req.body.email.length == 0) {
User.findOne({mobile: req.body.mobile}, contWithRegCallback);
} else if (req.body.mobile.length == 0) {
User.findOne({email: req.body.email}, contWithRegCallback);
} else {
User.findOne({$or: [{email: req.body.email}, {mobile: req.body.mobile}]}, contWithRegCallback);
}
Namely the user in the callback function keeps returning undefined. Shouldnt it be the contents fro the fineOne?
Why don't you just use conditional check?
This simple snippet should work as expected, notice, you want to filter by email or mobile.
var callback = function(err, result){
if(err) {
return res.status(400).send({message: 'Server error:' + JSON.stringify(err)});
} else {
res.json(result);
}
}
if (req.body.email){
User.findOne({email: req.body.email}, callback);
} else if (req.body.mobile) {
User.findOne({mobile: req.body.mobile}, callback);
} else {
return res.status(400).send({message: "Email or Mobile required"});
}