How to store value to var from another function - javascript

I'm comparing my two documents named: user and bloodrequest based on their id, if they match then display the values in the table bloodrequest that has the same id. My problem here is that I'm trying to store the current logged in user to a var like this : var permit = mainUser.branch_id then used a $where statement using this: this.chapter_id == permit but gives me error.
MongoError: TypeError: mainUser is undefined :
Here is my code, My only problem is how to pass mainUser.branch_id to var permit, I'm just starting to learn
router.get('/bloodapprovedrequestmanagement', function(req, res) {
User.find({}, function(err, users) {
if (err) throw err;
User.findOne({ username: req.decoded.username }, function(err, mainUser) {
if (err) throw err;
if (!mainUser) {
res.json({ success: false, message: 'No user found' });
} if (mainUser.branch_id === '111') {
Bloodrequest.find({$where: function(err) {
var permit = mainUser.branch_id//gives me error here
return (this.request_status == "approved" && this.chapter_id == permit) }}, function(err, bloodrequests) {
if (err) throw err;
Bloodrequest.findOne({ patient_name: req.decoded.patient_name }, function(err, mainUser) {
if (err) throw err;
res.json({ success: true, bloodrequests: bloodrequests });
});
});
}
});
});
});

Declare the variable outside the local scope.
`router.get('/bloodapprovedrequestmanagement', function(req, res) {
var permit;
User.find({}, function(err, users) {
if (err) throw err;
User.findOne({ username: req.decoded.username }, function(err, mainUser) {
if (err) throw err;
if (!mainUser) {
res.json({ success: false, message: 'No user found' });
}
if(mainUser.branch_id === '111') {
permit = mainUser.branch_id;
Bloodrequest.find({$where: function(err) {
return (this.request_status == "approved" && this.chapter_id == permit) }}, function(err, bloodrequests) {
if (err) throw err;
Bloodrequest.findOne({ patient_name: req.decoded.patient_name }, function(err, mainUser) {
if (err) throw err;
res.json({ success: true, bloodrequests: bloodrequests });
});
});
}
});
});
});`

Convert your callback to async await that more simple.
router.get('/bloodapprovedrequestmanagement', function async(req, res) {
try {
var permit;
let mainUser = await User.findOne({ username: req.decoded.username });
if(mainUser && mainUser.branch_id && mainUser.branch_id === '111') {
permit = mainUser.branch_id;
// here you add your condiion for (this.request_status == "approved" && this.chapter_id == permit).
let bloodRequestData = await Bloodrequest.findOne({ patient_name: req.decoded.patient_name });
res.json({ success: true, bloodrequests: bloodRequestData });
}
} catch (error) {
throw error
}
}
As per my understanding you have not used User.find({}) and Bloodrequest.find({}) data in your code.

Related

MongoDB Error 'Cannot read property '_id' of undefined'

I'm setting up a web-app with chat rooms for teachers and their students. Teachers will invite their students to the program and therefore I need to validate whether the students have an account already.
I've scoured the internet for solutions but none of the solutions are for the same issue as mine
function insertUsers(collectionName, userArray) {
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db('squeakdb');
for (var i=0; i<userArray.length; i++) {
dbo.collection(collectionName).find({ studentId: userArray[i].studentId }).toArray(function (err, res) {
console.log(res == '');
// If res == '' is true, it means the user does not already have an account
if (res == '') {
dbo.collection(collectionName).insertOne(userArray[i], function(error, result) {
if (error) throw error;
console.log('Inserted');
});
}
});
}
});
}
insertUsers('userlist', [{ 'studentId': 'STU0001' }, { 'studentId': 'STU0018', 'firstName': 'testName' }]);
The expected result is for the first object in the array to not be inserted into the database, and for the second object to be inserted.
The current result is the first object not being inserted (as expected) and the second object producing the following error:
TypeError: Cannot read property '_id' of undefined
I've discovered why the error occurred, it was caused by doing an asynchronous call inside a for loop. Here is the fixed code.
function insertUsers(collectionName, userArray) {
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db('squeakdb');
userArray.forEach(function (index){
dbo.collection(collectionName).find({ studentId: index.studentId }).toArray(function (err, res) {
console.log(res.length == 0);
if (res.length == 0) {
dbo.collection(collectionName).insertOne(index, function(error, result) {
if (error) throw error;
console.log('Inserted');
});
}
});
});
});
}

bcrypt.compare promise always returns false

I've looked through the other issues with bcrypt.compare on GitHub and none of the solutions have worked for me. It always fails on console.log("failed 3") inside bcrypt.compare()
I've tried switching the .then() instead of using a callback with bcrypt.compare as suggested by another post but that hasn't help. Any help would be greatly appreciated!
Below is a copy of my code and summary of versions being used:
Node v8.12.0
Express 4.16.0
bcrypt 3.0.3
jsonwebtoken 8.4.0
mongoose 5.4.1
Bcrypt Hash (Password Hashing)
function saveUserData(req, res, next, userSignUpInfo, info){
bcrypt.hash(req.body.email, 10, (err, hash) =>{
if (err){
return res.status(500).json({
error: err
})
} else {
console.log('inside test route')
console.log('req.body.fnUserName', userSignUpInfo.fnUserName)
const userData = new UserData({
fnUserName : userSignUpInfo.fnUserName,
password : hash,
email : req.body.email,
verify: userSignUpInfo.verify,
createAccountDate: userSignUpInfo.createAccountDate,
userId : userSignUpInfo.userId,
friends: null,
online: null
})
userData.save()
.then(result => {
console.log('result from MongoDB Cloud', result);
saveApiData(info, userSignUpInfo, res);
})
.catch(err => console.log('error from MongoDB Cloud', err));
}
})
}
Bcrypt Compare (Auth User)
router.post('/login', (req, res, next) => {
UserData.find({email: req.body.email})
.exec()
.then(user => {
if(user.length < 1) {
console.log("failed 1")
return res.status(401).json({
message: 'Authentication Failed'
});
}
console.log('user[0].password', user[0].password)
console.log(' user[0].password', user[0].password)
console.log(' req.body.password', req.body.password)
bcrypt.compare(req.body.password,user[0].password).then(function(err, result) {
if (err) {
console.log("failed 1")
return res.status(401).json({
message: 'Authentication Failed'
});
}
if (result) {
const token = jwt.sign(
{
email: user[0].email,
userId: user[0].userId
},
process.env.JWT_KEY,
{
expiresIn: "1h" // he suggested one hour
}
);
console.log("failed 2")
return res.status(200).json({
message: 'Authentication Successful',
token: token
})
} else {
console.log("failed 3")
res.status(401).json({
message: 'Authentication Failed'
})
}
})
})
.catch(err => {
console.log('err in login', err);
res.status(500).json({
error: err,
message: 'error logging in'
})
})
});
Usually, password is saved as hash in the database. Also, provide adequate length for saving hashes into database.(atleast 60 varchars). To do so,
schema.pre("save", function (next) {
bcrypt.hash(this.password, 10, (err, hash) => {
this.password = hash;
next();
});
});
Then, plain password is compared against the hash from database.
bcrypt.hash('mypassword', 10, function(err, hash) {
if (err) { throw (err); }
bcrypt.compare('mypassword', hash, function(err, result) {
if (err) { throw (err); }
console.log(result);
});
});
result will always be undefined since promises return a single value and errors are simply thrown in the catch phrase. So basically, in your code, err will contain the actual result.
What your code should look like is the following:
bcrypt.compare(req.body.password,user[0].password).then((result)=>{
if(result){
console.log("authentication successful")
// do stuff
} else {
console.log("authentication failed. Password doesn't match")
// do other stuff
}
})
.catch((err)=>console.error(err))
It looks like you don't return your res.status inside the
else { console.log("failed 3")
block like you do in the failed 2 and failed 1 blocks.

nodejs express response append into a list

I have multiple res.send in one route, how can I append them all into one and send the accumulated list at the end?
I prefer to do it in the following form:
{
"writer": {success message},
"archive": {success message},
...
}
and another one like above for the list errors.
here is the code:
router.post('/some/route', function (req, res) {
if (req.isLoggedIn()) {
return res.status(403).json({});
}
MyModel.findById(req.user._id,function (err, data) {
if(err || data.rights !== 'super'){
return res.status(403).json({});
}
if(req.body.writer){
Books.update(
{ writer : req.body.id},
{ $set : { writer : req.body.writer} },
function (err) {
if(err){
res.status(500).send(err);
}
else{
res.status(200).send('updated successfully.');
}
}
);
}else{
Books.remove({writer: req.body.id}, function(err){
if (err){ return console.log(err)}
});
}
MetaInfo.findOneAndRemove({_id: req.body.id}, function (err, data) {
console.log(err);
});
Archive.findOne({_id: req.body.id},function (err, data) {
smtpTransporter.sendMail({...}, function (error, response) {
if (error) {
console.log(error);
} else {
console.log("Mail sent");
}
smtpTransporter.close();
});
data.remove();
if (err) {
console.log(err);
return res.status(200).json({
success: false,
message: 'server error',
err: err
});
}
res.status(200).json({
success: true
});
})
});
});
I assume your problem are the asynchronous calls to the database.
So best take a library of your choice (for example async) and do your async processes, in the callback then finally send your result.
Your result could look like this:
async.parallel([
function(callback) { ... },
function(callback) { ... }
], function(err, results) {
// send your result here
});
Note that if you are using .parallel the final callback will be immediatly called if one of the promises fails. see the docu

How to do avoid huge nested if else

This is my code for logging in
method: 'POST',
path: '/api/login/sp',
config: { auth: false },
handler: function (request, reply) {
User.findOne({ phone: request.payload.phone }, function (err, user) {
if (err) throw err;
if (user !== null) {
user.comparePassword(request.payload.password, function (err, isMatch) {
if (err) throw err;
if (isMatch) { // Login success
data = {
"statusCode": 200,
"token": generateJWT(user._id)
}
return reply(data);
}
else {
reply(Boom.unauthorized('Invalid Account'))
}
});
}
else { // Invalid User
reply(Boom.unauthorized('Invalid Account'))
}
});
}
It takes a lot of code and makes it very hard to read. Is there a way to better write this part of the code so that it is easily maintainable and readable?
You may use return reply():
User.findOne({phone: request.payload.phone}, function (err, user) {
if (err) throw err;
if (user === null) return reply(Boom.unauthorized('Invalid Account'));
user.comparePassword(request.payload.password, function (err, isMatch) {
if (err) throw err;
if (!isMatch) return reply(Boom.unauthorized('Invalid Account'));
data = {
"statusCode": 200,
"token": generateJWT(user._id)
};
return reply(data);
});
})
Try using the return early pattern: Return early pattern for functions
User.findOne(..., {
// generic error
if (err) throw err;
// invalid user
if (user === null) {
reply(Boom.unauthorized('Invalid Account'));
return;
}
user.comparePassword(..., {
if (err) throw err;
if (!isMatch) {
reply(Boom.unauthorized('Invalid Account'));
return;
}
data = {
"statusCode": 200,
"token": generateJWT(user._id)
};
reply(data);
});
});

MongoDB $where is not working properly

I have looked around and tried all kinds of docs to be able to get the $where clause in MongoDB to work for me, but it just won't work.
Here is my object:
var UserProfiles = [{
userProfileID: "3f8c553c-3633-4fe9-a007-4346a783450c",
firstName: 'Austin',
lastName: 'Hunter',
email: 'ahunter8....com',
token: '',
platform: '',
password: 'admin',
companyProfileID: "86660a5b-7f61-4238-889d-1cc3087947b9",
authentication: ''
}....
there are several "profiles" inserted into the UserProfiles Object. That is just the first one.
Here is me inserting into the collection:
MongoClient.connect(url, function(err, db) {
if (err) {
console.log(err);
} else {
console.log("We are connected");
}
var collection = db.collection('UserProfile');
for (var i = 0; i < UserProfiles.length; i++) {
collection.insert(UserProfiles[i], function(err, result) {
if (err) {
console.log(err);
} else {
console.log(result);
}
});
}
db.close();
});
Now I am trying to search my collection for a passed in email AND companyProfileID. If they both match then return that profile. I thought the $where clause would be best but I can't get it to work.
Here is me trying to find():
function getUserProfile(passInEmail, companyID, callback) {
MongoClient.connect(url, function(err, db) {
if (err) {
console.log(err);
} else {
console.log("We are connected");
}
var collection = db.collection('UserProfile');
collection.find({$where: "this.email == passInEmail"}, function(err, result) {
if (err) {
console.log(err);
callback(err);
} else if (result.length) {
console.log(result);
callback(result);
} else {
callback(err);
console.log("No document found");
}
});
db.close();
});
}
I am trying to search the collection and if the object email matches the passed in email and the object companyProfileID matches the passed in companyID then success.
The $where clause in your case in not the best thing.
You should do simply:
//userIdParam ad emailParam are two variables
collection.find({userProfileID: userIdParam, email: emailParam})
.toArray(function(err, result) {
if (err) {
console.log(err);
callback(err);
} else if (result.length) {
console.log(result);
callback(result);
} else {
callback(err);
console.log("No document found");
}
});
Take a look of the doc here

Categories