Get data from findOne mongoose inside another findOne function - node.js

I am trying to get the candidate or HR (user roles) object using mongoose and nodejs. I have a user and both roles are derived from it.
when trying to connect using a UNIQUE username and a password. A user object will be sent as a result. I want to also send candidate/ or HR that are linked to that user.
I am passing the user object by reference to the candidate/HR schema:
const candidateSchema = new Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
index: true,
},
fullName: String,
profilePhoto: String,
birthday: Date,
I need to get the candidate object of the user that i get inside the exec() function. save it in a variable and send it as a res to signin function
app.post("/api/auth/signin", (req, res) => {
User.findOne({
username: req.body.username,
})
.populate("roles", "-__v")
.exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
const candi = candidat.findOne({ user: user }).exec((err, candidate) => {
//I want to save the candidate var
}));
//console.log("res",candi);
.....
});

A simple solution will be to wrap your code inside a promise and resolve whatever you want to store to variable while reject when you want to send error.
But its recommended to break down your code to multiple async functions and await them instead of using callback exec functions.
app.post("/api/auth/signin", async (req, res) => {
try{
let response = await new Promise((resolve,reject)=>{
User.findOne({
username: req.body.username,
})
.populate("roles", "-__v")
.exec((err, user) => {
if (err) {
//REJECT ERROR
reject(err);
return;
}
const candi = candidat.findOne({ user: user }).exec((err, candidate) => {
//RESOLVE YOUR CANDIDATE
resolve(canditate);
}));
//console.log("res",candi);
.....
});
.... your rest of code
})
res.send(response) // or required json
}catch(err){
res.status(500).send({ message: err });
}
}

Related

How to update user lastlogin time in react

i want to display last login time of user in table column after they logged in. i tried with some code in backend with nodejs and mongoose but sure it is not the right way. Can anyone help me how to handle it from backend and FE as well?
Here is Schema of user:
const userSchema = new Schema(
{
name: { type: String },
email: { type: String, unique: true},
password: { type: String },
status: {type: String, enum:["Active", "Blocked"], default:"Active"},
token: { type: String },
lastLogin: { type: Date, default: Date.now()},
},
{ timestamps: true }
);
Route:
userRouter.post("/login", async (req, res, next) => {
try {
const { email, password } = req.body;
if (!(email && password)) res.status(204).send({ msg: "All fields are required!" });
const user = await UsersModel.findOne({ email });
console.log(user);
if (user && (await bcrypt.compare(password, user.password))) {
const accessToken = await JWTAuthenticate(user);
user.token = accessToken;
user.lastLogin = Date.now()
res.status(200).send(user);
} else {
res.status(404).send({ msg: "User with this email not found!" });
}
UsersModel.findOneAndUpdate({lastLogin: Date.now()}, (err, data) => {
if(err) console.log(err);
else console.log("Successfully updated the lastLogin", data);
})
} catch (error) {
next(error);
}
});
You just have to call await user.save() after setting lastLogin (and remove findOneAndUpdate call)
or
actually query for the user in your findOneAndUpdate call. Currently you are querying for a 'lastLogin' field with the value now() which will never match. Adjust this call as following:
UsersModel.findByIdAndUpdate(user._id, {lastLogin: Date.now()}, (err, data) => {
if(err) console.log(err);
else console.log("Successfully updated the lastLogin", data);
})
Just a hint: JWTs are used for storing the session state on client side. You don't need to actually store these Tokens in your database. You just have to validate it on incoming request.

Fetch data from MongoDB when the user register

I am learning MEAN stack environment and I have a question.
I have a registration page, which registers the user in MongoDB:
// register.component.ts
register(){
this.http.post('http://localhost:3001/register', this.input)
.subscribe(
( next: any) => {
// TO-DO Success event
},
( error: any) => {
// TO-DO Error event
});
}
// app.js
app.post('/register', function(req, res){
db.collection('users').insertOne({
prenom : req.body.prenom,
nom: req.body.nom,
email : req.body.email,
password : req.body.password
})
})
It works pretty well, the problem is that for the connection, I use the _id:
// login.component.ts
login(id: string){
this.http.get('http://localhost:3001/login/' + id).toPromise().then((data: any) => {
this.users = data
})
sessionStorage.setItem('id', id)
}
// app.js
app.get('/login/:id', function(req, res){
db.collection('users').findOne({ email: ObjectId(`${req.params.id}`)}, function(err, user){
if (err) throw err;
if (!user) {
console.log('User not found')
}
else if (user)
{
console.log('Found user: ' + user.prenom)
}
})
})
How to make sure that when the user registers, it returns his _id directly, and like that I can put him in session:
sessionStorage.setItem('id', id)
The db.collection.insertOne() function returns the inserted document, see here. This means you can do a callback or async/await (whichever you prefer) for your insertOne() function and then return the _id by using the Express function res.json(). In your frontend, you'll then get whatever content you put into res.json() as a response. Happy coding! :)

TypeError: newUser.find is not a function

I am very new to the MERN stack and I would like some help figuring out this error. I'm trying to check if an email is already in the database upon creating a new user. Can anyone tell me why I am getting this error?
The model and scheme
//schema
const Schema = mongoose.Schema;
const VerificationSchema = new Schema({
FullName: String,
email: String,
password: String,
date: Date,
isVerified: Boolean,
});
// Model
const User = mongoose.model("Users", VerificationSchema);
module.exports = User;
The Api
const express = require("express");
const router = express.Router();
const User = require("../Models/User");
router.get("/VerifyEmail", (req, res) => {
console.log("Body:", req.body);
const data = req.body;
const newUser = new User();
newUser.find({ email: data.email }, function (err, newUser) {
if (err) console.log(err);
if (newUser) {
console.log("ErrorMessage: This email already exists");
} else {
console.log("This email is valid");
}
});
res.json({
msg: "We received your data!!!",
});
});
module.exports = router;
The api caller using axios
const isEmailValid = (value) => {
const info = {
email: value,
};
axios({
url: "http://localhost:3001/api/VerifyEmail",
method: "get",
data: info,
})
.then(() => {
console.log("Data has been sent");
console.log(info);
})
.catch(() => {
console.log("Internal server error");
});
};
if you have body in your request, change the type of request to POST...
after that for use find don't need to create a instance of model, use find with Model
router.get("/VerifyEmail", (req, res) => {
console.log("Body:", req.body);
const data = req.body;
User.find({ email: data.email }, function (err, newUser) {
if (err) console.log(err);
if (newUser) {
console.log("ErrorMessage: This email already exists");
} else {
console.log("This email is valid");
}
});
res.json({
msg: "We received your data!!!",
});
});
I prefer to use async/await and don't use Uppercase world for routing check the article: like this
router.post("/verify-email", async (req, res) => {
try {
let { email } = req.body;
let newUser = await User.findOne({ email });
if (newUser) {
console.log("ErrorMessage: This email already exists");
} else {
console.log("This email is valid");
}
} catch (error) {
res.json({
msg: "somthing went wrong",
});
}
res.json({
msg: "We received your data!!!",
});
});
The proper way to query a Model is like so:
const User = mongoose.model('Users');
User.find({<query>}, function (err, newUser) {...
So you need to get the model into a variable (in this case User) and then run the find function directly against it, as opposed to running it against an object you instantiate from it. So this is incorrect:
const newUser = new User();
newUser.find(...
So assuming all your files and modules are linked up correctly, this should work:
const User = require("../Models/User");
User.find({<query>}, function (err, newUser) {...
The problem wasn't actually the mongoose function but I needed to parse the object being sent.
let { email } = JSON.parse(req.body);
Before parsing the object looked like {"email" : "something#gmail.com"}
and after parsing the object looked like {email: 'something#gmail.com'}
I also changed the request from 'get' to 'post' and instead of creating a new instance of the model I simply used User.find() instead of newUser.find()

Node JS Mongoose Async Callbacks

I've got this piece of code that I seem to be getting in a bit of a muddle with.
What it does is create users. Now, if a user has a company, then that company should be created along with the user and linked accordingly. If the company already exists, then it shouldn't be created and it shouldn't be attributed to the user.
First the code looks for a company, if it can't find one then one is created. Life is good. But if I were to add an else to my "if (!company)" check i would be duplicating the majority of my create user code. I also believe I can't check the company and then run the user creation synchronously as I would usually do in a different language. Hence i'm getting a little stuck..
module.exports = {
postUsers: (req, res) => {
'use strict'
Company.findOne({name: req.body.company}, (err, company) => {
if (err) {
Logger.error(err)
return res.send(500, err)
}
if (!company) {
// only attribute a company if one doesn't exist
// don't want users to assign themselves to existing companies automatically
// need approval in place from an existing company member
let newCompanyToAdd = new Company({
name: req.body.company
})
newCompanyToAdd.save(err => {
if (err) {
Logger.error(err)
return res.send(500, err)
}
let user = new User({
username: req.body.username,
password: req.body.password,
firstname: req.body.firstname,
lastname: req.body.lastname,
company: newCompanyToAdd.id
})
user.save(err => {
if (err) {
return res.send(500, err)
}
res.status(200).json({ message: 'New User Added' })
})
})
}
})
}
EDIT#
postUsers: (req, res) => {
'use strict'
let user = new User({
username: req.body.username,
password: req.body.password,
firstname: req.body.firstname,
lastname: req.body.lastname
})
Company.findOne({name: req.body.company}, (err, company) => {
if (err) {
Logger.error(err)
return res.send(500, err)
}
if (!company && req.name.company !== undefined) {
// only attribute a company if one doesn't exist
// don't want users to assign themselves to existing companies automatically
// need approval in place from an existing company member
let newCompanyToAdd = new Company({
name: req.body.company
})
newCompanyToAdd.save(err => {
if (err) {
Logger.error(err)
return res.send(500, err)
}
user.company = newCompanyToAdd._id
})
}
})
user.save(err => {
if (err) {
return res.send(500, err)
}
res.status(200).json({ message: 'New User Added' })
})
}
I'm not totally sure I understand the overall goal. But seems like you're worried about having the add user code be replicated because you need to add the user regardless of if the company already exists or not. Is there any reason you can't save the user first, and in the callback, conditionally create the company if necessary?

Cannot update MongoDB using mongoose

I am trying to update a collection from my database using de node module mongoose. The problem is with $set updates. Here is my code:
// Update a user
app.patch('/user/:user_id', passport.authenticate('bearer', { session: false }),
function (req, res) {
var conditions = { _id: new ObjectId(req.params.user_id)},
updateObj = { $set: req.body }; // {email : "bob#example.com", username: "bob"}
User.update(conditions, updateObj, function callback (err, numAffected, rawResponse) {
if (err) {
res.send(err);
return;
}
// numAffected is the number of updated documents
if (numAffected == 0) {
res.json({ message: 'No user affected'});
return;
}
res.json({ message: 'User updated'});
});
});
If I update an existing key like email, it is updated. But if I want to add a new key, numAffected is always 0 and the rawResponse is undefined.
Any idea of what happens?
Edit
Here is my Schema:
var userSchema = mongoose.Schema({
email : String,
username : String,
password : String
});
In order to set multiple fields in a document, you must set the Multi option in your config, otherwise Mongoose will ignore the continuation, and only update the first doc.
From the docs:
var conditions = { name: 'borne' }
, update = { $inc: { visits: 1 }}
, options = { multi: true };
Model.update(conditions, update, options, callback);
function callback (err, numAffected) {
// numAffected is the number of updated documents
});
Another note here: The numAffected should return as expected, but I can't find any documentation on their site about the raw response, but it should return as expected as well. Do you know of any documentation for this?
I think this is what you really want to do with mongoose to update email and username of a user.
app.patch('/user/:user_id', passport.authenticate('bearer', { session: false }),
function (req, res) {
User.findOneAndUpdate({_id: req.params.user_id},
{
$set: {
username: req.body.username,
email: req.body.email
}
}, function(err, user) {
if (err)
res.send(err);
if (user) {
res.json({message: 'User updated'});
} else {
res.json({message: 'User does not exist'});
}
});
});

Resources