.then is undefined when I try to save in MongoDB - javascript

I'm new to node.js.
I got this message:
TypeError: Cannot read property 'then' of undefined
Here is the code:
router.post("/signup", (req, res) => {
const userRegister = new UserRegister({
_id: new mongoose.Types.ObjectId(),
nickname: req.body.nickname,
email: req.body.password,
password: req.body.password,
level: 0
});
console.log(req.body.nickname + " " + req.body.email + " " + req.body.password);
userRegister
.save()
.then(doc => {
console.log(doc);
res.status(200).json({
message: "User created"
});
})
.catch(err => {
if (err)
console.log("error => " + err)
res.status(409).json({
message: "ERROR"
})
});
});
and the Schema:
const mongoose = require("mongoose");
const userRegister = mongoose.Schema({
_id : mongoose.Schema.Types.ObjectId,
nickname: String,
email: String,
password: String,
level: Number
});
module.exports = mongoose.model("UserRegister", userRegister);
I don't really understand why it says ".then undefined".
(the body is good)

It seems like function "save" does not return Promise. But in source code it does...
https://github.com/Automattic/mongoose/blob/master/lib/model.js#L385
Also you can try "create" method.
https://github.com/Automattic/mongoose/blob/master/lib/model.js#L2646
Maybe it will be hellpfull:
const result = new SomeModel({...});
new Promise((resolve, reject) => {
// Save model
result.save(err => {
if (err) {
return reject(new Error(`Error with exam ersult save... ${err}`));
}
// Return saved model
return resolve(result);
})
.then(res => {
return res;
})
.catch(err => {
throw new Error(err);
});

check if the model is the promising type or not if this is not the promising then use callback
mongoose promises
assert.ok(user instanceof Promise); // this return ture or false
router.post("/signup", (req, res) => {
const userRegister = new UserRegister({
_id: new mongoose.Types.ObjectId(),
nickname: req.body.nickname,
email: req.body.password,
password: req.body.password,
level: 0
});
console.log(req.body.nickname + " " + req.body.email + " " + req.body.password);
var user = userRegister.save()
assert.ok(user instanceof Promise);
// if assert.ok return true then use user.then
// else use callback userRegister.save( function(doc){ })
user.then(doc => {
console.log(doc);
res.status(200).json({
message: "User created"
});
})
.catch(err => {
if (err)
console.log("error => " + err)
res.status(409).json({
message: "ERROR"
})
});
});

router.post("/signup", async (req, res) => {
try{
const userRegister = await UserRegister.create({
_id: new mongoose.Types.ObjectId(),
nickname: req.body.nickname,
email: req.body.password,
password: req.body.password,
level: 0
});
}
catch(err){
console.log("error => " + err)
res.status(409).json({
message: "ERROR"
})
}
console.log(userRegister);
res.status(200).json({
message: "User created"
});
});

Related

How to integrate msg91 api with node

I am trying mobile verification with msg91 ..the code run succesfully but msg notsending messagee...it gives the success message ...
my code:
router.post('/mobile', async (req, res) =\> {
try {
const sendOtp = new SendOtp(process.env.AUTHKEY);
const mobile = await usermodel.findOne({ mobile: req.body.mobile })
if (!mobile) return res.status(403).send('user not found..')
const otp =`${ Math.floor(1000 + Math.random() * 9000)} `
console.log(otp);
const phonenumber = req.body.mobile
const newPhoneNumber = '+91' + phonenumber
// console.log(newPhoneNumber);
sendOtp.send(newPhoneNumber, otp, function (error, data) {
console.log(data);
console.log(error);
});
res.status(201).send({ status: 'TRUE', message: 'OTP SEND' })
} catch (error) {
res.status(200).send({ status: 'failed', message: 'Unable to Send OTP', error })
console.log(error)
}
})
responce:
{ message: '326b6774704a343230323437', type: 'success' }
null

Why am I getting Promise Pending despite using await in my controller?

I have a repository where I connect directly to my model to insert some data, it creates the data successfully but when I connect my controller to this repository, I get a nulled response, if I log it in the repository itself I get Promise . Please checkout my code below:-
Repository.js
exports.register = (request) => {
const data = UserModel.findOne({email: request.email})
.then(user => {
if(user)
{
return {status: 400, message: 'Email Already exist'}
} else {
return bcrypt.genSalt(10, (err, salt) => {
const newUser = new UserModel({
username: request.username,
email: request.email,
password: request.password
});
return bcrypt.hash(newUser.password, salt, async (err, hash) => {
if(err) throw err;
newUser.password = hash;
return newUser.save()
.then(user => {
const token = jwt.sign({id: user._id}, process.env.JWT_SECRET, {
expiresIn: 86400 // expires in 24 hours
});
return {status: 200, message: 'Successfully Registered', auth: true, token: token, user: user}
})
.catch(err => {
return {status: 400, message: err}
})
})
})
}
})
console.log(data) // This part is return Promise <pending>
return data;
};
Controller.js
exports.SeedRegisteration = async (req, res, next) => {
try {
let element = await userRepo.register({username: "Testin", email: "Testin#test.com", "password":
"joe" });
return await res.status(200).json({ status: 200, data: element })
} catch (e) {
return res.status(400).json({ status: 400, message: e.message });
}
};
Works fine but does not return data
Here's the register function using the Promise version of bcrypt (if you don't supply a callback, the bcrypt functions return a Promise
exports.register = (request) =>
UserModel.findOne({
email: request.email
})
.then(user => {
if (user) {
throw 'Email Already exist'
}
})
.then(() => bcrypt.genSalt(10))
.then(salt => {
const newUser = new UserModel({
username: request.username,
email: request.email,
password: request.password
});
return bcrypt.hash(newUser.password, salt)
.then((hash) => {
newUser.password = hash;
return newUser.save();
})
}).then(user => {
const token = jwt.sign({
id: user._id
}, process.env.JWT_SECRET, {
expiresIn: 86400 // expires in 24 hours
});
return {
status: 200,
message: 'Successfully Registered',
auth: true,
token: token,
user: user
}
}).catch(err => {
return {
status: 400,
message: err
}
});
Note: there is ONE nested .then - this code could be perfectly flat if you used async/await in register - however I was not prepared to perform such a big rewrite for the answer. Now that the code is in a nice almost flat promise chain, it's relatively simple to convert the whole thing into async/await style
There are too many return statements which return promise. Please update your code in to the following:
exports.register = (request) => {
return new Promise((resolve, reject) => {
try {
UserModel.findOne({ email: request.email })
.then(user => {
if (user) {
return reject({ status: 400, message: 'Email Already exist' })
} else {
bcrypt.genSalt(10, (err, salt) => {
const newUser = new UserModel({
username: request.username,
email: request.email,
password: request.password
});
bcrypt.hash(newUser.password, salt, async (err, hash) => {
if (err) return reject(err);
newUser.password = hash;
newUser.save()
.then(user => {
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, {
expiresIn: 86400 // expires in 24 hours
});
return resolve({ status: 200, message: 'Successfully Registered', auth: true, token: token, user: user })
})
.catch(err => {
return reject({ status: 400, message: err })
})
})
})
}
}).catch(err => {
return reject(err)
})
} catch (error) {
return reject(error)
}
});
};

Object is returned the same although I'm mutating it

The upcoming code snippet is removing the password attribute from the user JSON object and return it in response. what is happening is that the password attribute is still returning!
const signin = (req, res, next) => {
let requestBody = req.body;
userModel.findUserByEmail(requestBody.email).then(user => {
bcrypt.compare(requestBody.password, user.password, (error, result) => {
if (!result) {
return res.status(500).json({
status: false,
message: 'Auth Failed!',
error
});
}
if (error) {
return res.status(500).json({
error
});
}
let token = jwt.sign({
email: user.email,
userId: user._id
},
process.env.JWT_KEY,
{
expiresIn: "2h"
});
// remonve password key
delete user.password
res.status(200).json({
status: true,
message: 'Authenticated!',
data: {
token,
user
}
});
});
}).catch(error => {
return res.status(500).json({
status: false,
message: 'Auth Failed!',
error
});
});
}
not sure the problem is related to async compilation or not
You could create a new object without the password and use that in your response:
const { password, ...restOfUser } = user
res.status(200).json({
status: true,
message: 'Authenticated!',
data: {
token
user: restOfUser
}
})

How to migrate my mongoose PROMISE chain transactions to ASYNC / AWAIT flow?

I created an API that integrate database responses in a promise flow, but I think the interpretation of the code is complex and I believe that async / await approach could improve both understanding and the code itself.
The API is built in NodeJS using mongoose 5.6.1 and express 4.17.1.
Can you help me in improve this?
Below is the API that I want to improve:
/** New employee */
router.post('/', (req, res) => {
let { idCompany, name, departament } = req.body;
let _id = mongoose.Types.ObjectId(); // Generating new MongoDB _ID
let employeeCreated;
const promise1 = new Promise((resolve, reject) => {
// Querying by document '$oid'
Companies.findOne({ _id: idCompany }, (err, company) => {
// Error returned
if (err) reject({ error: "Invalid request, something went wrong!" });
// Invalid data received
if (!company) reject({ error: "Unauthorized action!" });
// Everything OK
resolve(company);
});
})
.then(company => {
if(company) {
const promise2 = new Promise((resolve, reject) => {
Employees.create({ _id, idCompany, name, departament }, (err, employee) => {
// Error returned
if (err) reject({ error: "Invalid request, something went wrong!", err });
// Everything OK
employeeCreated = employee;
resolve(company);
});
})
return promise2;
}else reject({ error: "Company not found!" });
})
.then(company => {
let { name: companyName, address, email, tel, employees } = company;
employees.push(_id);
const promise3 = new Promise((resolve, reject) => {
Companies.findByIdAndUpdate(
{ _id: idCompany },
{ $set: { _id: idCompany, name: companyName, address, email, tel, employees } }, // spotlight
{ new: true },
(err, company) => {
// Something wrong happens
if (err) reject({ success: false, error: "Can't update company!" });
// Everything OK
resolve(company);
}
);
});
return promise3;
});
promise1
.then(() => res.json({ success: true, employeeCreated }))
.catch(err => res.status(400).json({ error: "Invalid request, something went wrong!", err }));
});
Regards.
One key to using promises with mongoose, is using the exec method:
Your code could then look something like this (not tested):
router.post('/', async (req, res) => {
try {
const { idCompany, name, departament } = req.body;
const _id = mongoose.Types.ObjectId();
const company = await Companies.findOne({ _id: idCompany }).exec();
const employeeCreated = await Employees.create({ _id, idCompany, name, departament });
const { name: companyName, address, email, tel, employees } = company;
employees.push(_id);
await Companies.findByIdAndUpdate(
{ _id: idCompany },
{ $set: { _id: idCompany, name: companyName, address, email, tel, employees } }, // spotlight
{ new: true }).exec();
res.json({ success: true, employeeCreated });
} catch(err) {
res.status(400).json({ error: "Invalid request, something went wrong!", err });
}
});
You could throw some specific custom errors in the try block if you find that necessary.
You could simply make the functions where your promises are running async and so, you could await for the promises to resolve.
For example, in your route use this:
router.post('/', async (req, res) => {
and then when performing an async operation, use this:
const company = await Companies.findOne({ _id: idCompany }).exec();
Also, I would suggest you to wrap this with try and catch statments
Hope it helps!

Cannot set headers after they are sent to the client with mongoose and node.js

I'm trying to make a registration function for users. I want to check first if the email exist, if so return a json
{ message: 'cannot register a new user' }
or else a json with confirmation and registered user details.
this code works fine, however the compiler says:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
its seems the the problem is this line:
res.status(200).json({ message: 'A new user was created!', user: result });
but I don't know how fix it so it won't make this message
my code is:
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const User = require('../models/user');
exports.signup = async (req, res, next) => {
const firstname = req.body.firstname;
const lastname = req.body.lastname;
const email = req.body.email;
const password = req.body.password;
try {
let canRegister = await User.findOne({ email: email })
.then(user => {
if (!user) {
return true;
}
res.status(400).json({ message: 'Email is already in use' });
})
.catch(err => {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
});
let addUser = await bcrypt
.hash(password, 12)
.then(hashedPw => {
const user = new User({
firstname: firstname,
lastname: lastname,
email: email,
password: hashedPw
});
return user.save();
})
.then(result => {
res.status(200).json({ message: 'A new user was created!', user: result });
})
.catch(err => {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
});
} catch {
res.status(400).json({ message: 'Email is already in use' });
}
};
You are trying to send the response twice.
let canRegister = await User.findOne({ email: email })
.then(user => {
if (!user) {
return true;
}
// You might have executed this 1st - and continue.
res.status(400).json({ message: 'Email is already in use' });
})
.catch(err => {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
});
But your code doesn't exit. It moves onto the next block.
let addUser = await bcrypt
.hash(password, 12)
.then(hashedPw => {
const user = new User({
firstname: firstname,
lastname: lastname,
email: email,
password: hashedPw
});
return user.save();
})
.then(result => {
// Then you are sending status again with this line.
res.status(200).json({ message: 'A new user was created!', user: result });
})
.catch(err => {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
});
You should figure out after canRegister is assigned (await block is complete) and return appropriately before proceeding to the next block.
Something like this:
let canRegister = await User.findOne({ email: email })
.then(user => {
if (!user) {
return true;
}
return false;
// Don't use the res.status here.
})
.catch(err => {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
});
if (!canRegister) {
return res.status(400).json({ message: 'Email is already in use' });
}

Categories

Resources