MongoDb findOne query results in error - even if data is found - node.js

the below is my controller function
exports.validateUsername = async (uName) => {
console.log("inside validate username");
await User.findOne({ username: "sab2" }).then(function (err, user) {
if (err) {
console.log("inside err");
console.log("error");
console.log(err);
return true;
} else {
console.log("inside user found");
console.log("user");
console.log(user);
return false;
}
});
};
I have record in my "user" collection with username ="sab2". But still , the promise function results in err, and goes inside if(err).
But when I do console.log(err) I get the actual user data "sab2" object.
I have a doubt if the function syntax is function(data,err).
Error object printed
Please suggest a solution.

The then() on a findOne does not return a error, I would rewrite like this:
User.findOne({ username: "sab2" }, function(err, user) {
if (err) {
console.log("inside err");
console.log("error");
console.log(err);
return true;
} else {
console.log("inside user found");
console.log("user");
console.log(user);
return false;
}
});

then do not return error. Do something like this to catch error
await User.findOne({ username: "sab2" }).then((user) => {
console.log(user)
}).catch(error=>console.log(error))
or use callback. See here

Related

When you delete user let the user posts get deleted too in node js

Please am finding it difficult to delete user and also get the user posts removed automatically. I can only delete user or the user posts separately but I want it in a way that when I delete the user from the database the user posts also get deleted
You can look into mongoose pre middleware something like this should work:
UserSchema.pre('remove', function (next) {
let id = this._id
Post.deleteMany({ user: id }, function (err, result) {
if (err) {
next(err)
} else {
next()
}
})
})
The call the middleware like this :
User.findById(id, function (err, doc) {
if (err) {
console.log(err)
return res.status(500).send('Something went wrong')
} else {
if (!doc)
return res.status(404).send('User with the given id not found')
doc.remove(function (err, postData) {
if (err) {
throw err
} else {
return res.send('User successfully deleted')
}
})
}
})

Finish execution if first query returns a value Node.js Express.js mongoDB

Before starting, please mind that i have been searching this over 2+ hours, the answer will be simple i know but i couldnt get it to work . i am new to express node mongodb,
MongoClient.connect(url, function(err, db) {
if (err) {
res.status(err.status); // or use err.statusCode instead
res.send(err.message);
}
var usernameGiven = req.body.usernameGiven;
//Select the database
var dbo = db.db("notifellow");
//run the query
var query = { username: usernameGiven , friends: []};
dbo.collection("users").findOne({ username: usernameGiven}, function(err, result) {
if (err){
res.status(err.status); // or use err.statusCode instead
res.send(err.message);
console.log("Query Error Occured!");
}
else {
if (result) {
//Send the response
res.send("EXISTS");
//I WOULD LIKE TO EXIT IF THIS LINE EXECUTES
}
}
});
dbo.collection("users").insertOne(query, function(err, result) {
if (err){
res.status(err.status); // or use err.statusCode instead
res.send(err.message);
console.log("Query Error Occured!");
}
else {
if (result) {
//Send the response
res.send("CREATED 201");
} else {
res.send("Failed to insert");
}
}
});
db.close();
});
my goal is to check if an user doesnt exists with given username, i would like to insert that to the DB.
i would like to exit if my query finds an match and arrange such that insertOne wont execute. please enlighten me!!
Once you are not using the async/await syntax you will have to nest the calls to MongoDB, so they execute in series. You can also use a module like async to achieve this.
MongoClient.connect(url, function(err, db) {
if (err) {
res.status(err.status); // or use err.statusCode instead
res.send(err.message);
}
var usernameGiven = req.body.usernameGiven;
//Select the database
var dbo = db.db("notifellow");
//run the query
var query = { username: usernameGiven , friends: []};
dbo.collection("users").findOne({ username: usernameGiven}, function(err, result) {
if (err){
res.status(err.status); // or use err.statusCode instead
db.close();
console.log("Query Error Occured!");
return res.send(err.message);
}
if (result) {
db.close();
return res.send("EXISTS");
}
dbo.collection("users").insertOne(query, function(err, result) {
if (err){
res.status(err.status); // or use err.statusCode instead
db.close();
console.log("Query Error Occured!");
return res.send(err.message);
}
db.close();
if (result) {
return res.send("CREATED 201");
}
res.send("Failed to insert");
});
});
});
Try this
dbo.collection("users").findOne({ username: usernameGiven}, function(err, result) {
if (err){
//put the error logic
}
else {
if (result) {
//Send the response
return result;
}
else{
// if above if block fails it means that user does not exist
//put the insert logic
}
});

Bluebird promise resolve is being caught as an error

I am using promises to return data for a user do authenticate them and my resolve is showing up in my .catch for my call.
Call to the login function;
function(req, username, password, done) {
user.login(username, password).then( function(err, results){
if (err) throw err;
done(null, results.user);
}).catch(
function(err){
console.log("Failed to log in", err);
done(null, false);
}
);
}
Here is the promise code:
exports.login = function(username, password){
return new promise(function(resolve, reject){
var sql = `CALL LOGIN(?)`;
db.conn.query(sql, username, (err, results, fields) => {
if (err) {
reject("SQL ERR:", err);
}
var user = results[0][0];
if (!user.uID) {
reject("Incorrect username");
}
if(bcrypt.compareSync(password, user.pword)){
resolve(user);
} else {
reject('Incorrect password');
}
});
});
}
When this is called, the user objet is being thrown as an error even though its being called on resolve... I am currently stuck, I tried to re-install the bluebird module as well incase something happened with it.
What's going on here is the next thing:
Here you are passing the user object as a param if everything is ok
if (bcrypt.compareSync(password, user.pword)) {
resolve(user);
} else {
reject('Incorrect password');
}
So in this part .then of your code you are receiving a user object as a unique param so there is no necessity to check if there is an error.
function (req, username, password, done) {
user.login(username, password).then(function(user) {
// a good way to see all arguments is
// console.log(arguments);
done(null, user);
}).catch(
function(err) {
console.log("Failed to log in", err);
done(null, false);
}
);
}

How to Async Mongoose Controller

Trying to configure a SignUp() controller that can update multiple (separate) user accounts when a referral code is provided by the user.
Basic Flow:
Verify email doesn't already exist in system
Find the driver w/ userID matching the rider's refCode (FindOneAndUpdate)
If Found: Add the userID of each user to the other users [clients] list
Only need to do a refCode match if isRider
If any of those fail... Return the specific error to the client/user
This does not work. But essentially, this is what I'm trying to accomplish...
// POST `/signup` (Create a new local user)
export function signUp(req, res, next) {
const newUser = new User({
email: req.body.email,
password: req.body.password,
profile: {
userID: req.body.userID,
refCode: req.body.refCode,
isRider: req.body.isRider
}
});
User.findOne({ email: req.body.email }, (findErr, foundUser) => {
if (foundUser) {
return res.status(409).send('This e-mail address already exists');
}
// riders must link to a driver
if (req.body.isRider) {
// find driver + add rider ID to clients
return User.findOneAndUpdate({ 'profile.userID': req.body.refCode }, { $push: { clients: newUser.profile.userID }}).exec()
.then((err, foundDriver) => {
if (err) {
return res.status(409).send('Error searching for driver');
} else if (!foundDriver) {
return res.status(409).send(`We can't find your driver (${req.body.refCode})!`);
}
// add driver ID to rider's clients
newUser.clients = [req.body.refCode];
return newUser.save((saveErr) => {
if (saveErr) return next(saveErr);
return req.logIn(newUser, (loginErr) => {
if (loginErr) return res.sendStatus(401);
return res.json(newUser.profile);
});
});
});
}
return newUser.save((saveErr) => {
if (saveErr) return next(saveErr);
return req.logIn(newUser, (loginErr) => {
if (loginErr) return res.sendStatus(401);
return res.json(newUser.profile);
});
});
});
}
Tried to configure it as a pure promise but no luck. Most of the examples out there all seem different to me... Also could not figure out how to handle/throw specific errors using the mongoose docs.
Greatly appreciated if anyone can lend a hand, Thx!
UPDATE:
Ippi's answer helped a ton - Thx!
This does the trick. Remember to return null from .then() after the req.login stuff to avoid warnings - Any tips on how to improve this are appreciated - Thx!
const createUser = (foundUser) => {
if (foundUser) { throw new Error('This e-mail address already exist.'); }
if (!req.body.isRider) { return newUser.save(); }
return User.findOneAndUpdate({ 'profile.userID': req.body.refCode.toLowerCase() }, { $push: { clients: newUser.profile.userID }}).exec()
.then((driver) => {
if (!driver) { throw new Error('We can\'t find your driver.'); }
newUser.clients = [req.body.refCode];
return newUser.save();
})
.catch(() => { throw new Error('There was a database error.'); });
};
User.findOne({ email: req.body.email }).exec()
.then(createUser)
.then((user) => {
if (user.profile) {
req.logIn(user, (loginErr) => {
if (loginErr) return res.sendStatus(401);
return res.status(200).send({ profile: user.profile, clients: user.clients });
});
} else { res.status(409); }
return null;
})
.catch((err) => { return res.status(409).send(err.message); });
function signUp(req, res, next) {
return new Promise((resolve, reject) => {
const newUser = new User({
email: req.body.email,
password: req.body.password,
profile: {
userID: req.body.userID,
refCode: req.body.refCode,
isRider: req.body.isRider
}
});
User.findOne({ email: req.body.email }, (findErr, foundUser) => {
if (foundUser) {
// return res.status(409).send('This e-mail address already exists');
reject('This e-mail address already exists');
}
// riders must link to a driver
if (req.body.isRider) {
// find driver + add rider ID clients
return User.findOneAndUpdate({ 'profile.userID': req.body.refCode }, { $push: { clients: newUser.profile.userID } }).exec()
.then((err, foundDriver) => {
if (err) {
// return res.status(409).send('Error searching for driver');
reject('Error searching for driver');
} else if (!foundDriver) {
// return res.status(409).send(`We can't find your driver (${req.body.refCode})!`);
reject(`We can't find your driver (${req.body.refCode})!`);
}
// add driver ID to rider's clients
newUser.clients = [req.body.refCode];
newUser.save((saveErr) => {
if (saveErr)
// next(saveErr);
reject(saveErr);
req.logIn(newUser, (loginErr) => {
if (loginErr)
// return res.sendStatus(401);
reject('401');
// return res.json(newUser.profile);
resolve(newUser.profile);
});
});
});
}
newUser.save((saveErr) => {
if (saveErr)
// return next(saveErr);
reject(saveErr);
req.logIn(newUser, (loginErr) => {
if (loginErr)
// return res.sendStatus(401);
reject(loginErr);
// return res.json(newUser.profile);
resolve(newUser.profile);
});
});
});
});}
This is how I would do it. I couldn't be bothered to try with express or the login (you need to replace console.log with res.status().json()) and I might have done some other blunder in the logic with the driver. But other than that I tested it with local mongo and it probably works and if nothing else it's a little bit more concise.
let updateUser = user => {
if (user){ throw new Error("USER_EXIST"); }
if (!req.body.isRider) { return newUser.save() }
return User.findOneAndUpdate({ 'profile.userID': req.body.refCode },{ $push: { clients: newUser.profile.userID }}).exec()
.then(driver => {
if (!driver) { throw new Error("NO_DRIVER");}
newUser.clients.push(req.body.refCode);
return newUser.save();
});
}
User.findOne({ email: req.body.email }).exec()
.then(updateUser)
.then(req.logIn) // newUser.save() response is passed in as is (I have not tested this line.)
.then( ()=>{ return console.log('profile', newUser.profile); })
.catch( Error, err => {
if (err.message == "USER_EXISTS") return console.log ("This e-mail address already exist." );
if (err.message == "NO_DRIVER") return console.log ("We can't find your driver." );
throw err;
});
Something worth remembering:
Callback calls or res.send should always go in the last then / catch. Calling res.send in middle of chains leads to trouble.

how to use Promise with express in node.js?

I am using Promise with Express.
router.post('/Registration', function(req, res) {
var Promise = require('promise');
var errorsArr = [];
function username() {
console.log("1");
return new Promise(function(resolve, reject) {
User.findOne({ username: req.body.username }, function(err, user) {
if(err) {
reject(err)
} else {
console.log("2");
errorsArr.push({ msg: "Username already been taken." });
resolve(errorsArr);
}
});
});
}
var username = username();
console.log(errorsArr);
});
When I log errorsArray, it is empty and I don't know why. I am new in node.js. Thanks in advance.
Try the following, and after please read the following document https://www.promisejs.org/ to understand how the promises work.
var Promise = require('promise');
router.post('/Registration',function(req,res,next) {
function username() {
console.log("agyaaa");
return new Promise(function(resolve,reject) {
User.findOne({"username":req.body.username}, function(err,user) {
if (err) {
reject(err)
} else {
console.log("yaha b agyaaa");
var errorsArr = [];
errorsArr.push({"msg":"Username already been taken."});
resolve(errorsArr);
}
});
});
}
username().then(function(data) {
console.log(data);
next();
});
});
You can have other errors also (or things that shouldn't be done that way). I'm only showing you the basic use of a Promise.
router.post('/Registration', function(req, res) {
return User
.findOne({ username: req.body.username })
.then((user) => {
if (user) {
return console.log({ msg:"Username already been taken" });
}
return console.log({ msg: "Username available." });
})
.catch((err)=>{
return console.error(err);
});
});
you can write a clean code like this.
Promise is a global variable available you don't need to require it.

Resources