Mongoose How to await updating documents? - node.js

im trying to figure out why my code isnt awaiting the update method in mongoose.
First I have tried to find the user
//Find user
const user = await User.findOne({
username,
active: { $ne: false },
accessBanExpires: { $lt: Date.now() },
}).select('+password');
//Update the user property
let newuser;
if (remember) {
if (!user.rememberAcct) {
newuser = await User.findOneAndUpdate(user._id, {
rememberAcct: true,
});
console.log('check: ', user.rememberAcct);
}
} else if (user.rememberAcct) {
await user.updateOne({
rememberAcct: false,
});
}
console.log(user.rememberAcct, newuser); //Here document always updating asyncrounously, but await seems not applying to update. newUser returns the user with old property
document always updating asyncrounously, but await seems not applying to update. newuser returns the user with old property
Update:
with options {returnDocument: 'after'} or {new: true} is still returning old document.
Refers: https://mongoosejs.com/docs/api.html#model_Model-findOneAndUpdate
What Im missing here?
newuser = await User.findOneAndUpdate(user._id, {
rememberAcct: true,
}, {returnDocument: 'after'});

In your snippet, there are 3 mistakes
1st
const user = await User.findOne({
username,
active: { $ne: false },
accessBanExpires: { $lt: Date.now() },
}).select('+password') // <-- missing `rememberAcct` to select, without it `user.rememberAcct` will always be `undefined`
2nd
await user.updateOne({ // <-- this should be `User` not `user`
rememberAcct: false, // <-- this filter will select a random user & update query is missing
})
3rd :- Not using user.save() to update user.
here is final solution.
const user = await User.findOne(
{
username,
active: { $ne: false },
accessBanExpires: { $lt: Date.now() },
},
{ password: 1, rememberAcct: 1 }
)
if (!user) throw new Error('user not found')
console.log('user.rememberAcct (before)', user.rememberAcct)
if (remember) {
if (!user.rememberAcct) {
user.rememberAcct = true
await user.save()
}
} else if (user.rememberAcct) {
user.rememberAcct = false
await user.save()
}
// NOTE: above `if/else` statements can be boiled down into single `if/else` statement, no need to check more than once.
// I leave it you figure it out.
console.log('user.rememberAcct (after)', user.rememberAcct)

Your should either use findByIdAndUpdate, or pass a proper query:
// Either:
await User.findByIdAndUpdate(
user._id,
{
rememberAcct: true
},
{
returnDocument: 'after'
}
);
// Or:
await User.findOneAndUpdate(
{
_id : user._id,
},
{
rememberAcct: true
},
{
returnDocument: 'after'
}
);

I believe you need to place them into a try catches, let me know if the below works
this ads some error handling as well so you know why it may have failed.
async function yourfunctionorrequest() {
let password
try {
const user = await User.findOne({
username,
active: {
$ne: false
},
accessBanExpires: {
$lt: Date.now()
},
}, function (err, docs) {
// set the specific item you were after to the variable
password = docs.password
})
} catch (e) {
console.log(e)
}
let newuser;
if (remember) {
if (!user.rememberAcct) {
try {
newuser = await User.findOneAndUpdate(user._id, {
rememberAcct: true,
});
console.log('check: ', user.rememberAcct);
} catch (e) {
console.log(e)
}
} else if (user.rememberAcct) {
try {
await user.updateOne({
rememberAcct: false,
});
} catch (e) {
console.log(e)
}
}
console.log(user.rememberAcct, newuser); //Here document always updating asyncrounously, but await seems not applying to update. newUser returns the user with old property
console.log("error message", e)
}
}

Related

MongoDB saves the necessary data to the collection, but outdated data goes to res()

Everything works fine, but the data I get in res() is one step behind. I rewrote the entire code a hundred times and no longer understand what the problem is
here is part of the code backend on express.js, node.js and mongodb:
export const addToCart = async (req, res) => { try {
const cart = await CartModul.findOne({ user: req.userId });
if (cart) {
const product_id = req.body.product_id;
const item = cart.cartItems.find((c) => c.product_id == product_id);
console.log("item", item);
if (item) {
try {
const cart = await CartModul.findOneAndUpdate(
{ user: req.userId, "cartItems.product_id": product_id },
{
"cartItems.$": {
...req.body,
quantity: item.quantity + req.body.quantity,
totalPrice: item.totalPrice + req.body.price,
},
}
);
if (cart) {
return res.status(200).json({ cart });
}
} catch (error) {
return res.status(400).json({ error });
}
} else {
try {
const cart = await CartModul.findOneAndUpdate(
{ user: req.userId },
{
$push: {
cartItems: req.body,
},
}
);
if (cart) {
return res.status(200).json({ cart });
}
} catch (error) {
return res.status(400).json({ error });
}
}
} else {
try {
const cart = new CartModul({
user: req.userId,
cartItems: req.body,
});
cart.save();
res.json(cart);
} catch (error) {
return res.status(400).json({ error });
}
} } catch (error) {
return res.status(400).json({ error })}};
In the else condition add await. i.e.
let newCart = await cart.save();
res.json(newCart);
Use {new: true) in findOneAndUpdate() and make async in moment with save()

Node express check mongo object id exists in array if not exist then update

I have a list of array in mongo what I need to do is push Id in list of array and check that if Id exist then it will not push
Right now I push like this
const eventUserGoing = async (req, res) => {
try {
const updateuserGoinginEvent = await Events.findByIdAndUpdate(
req.body.eventid,
{
$push: {
userGoing: req.user.user_id,
},
},
{
new: true,
}
);
res
.status(200)
.json({
success: true,
message: 'Event saved successfully',
data: updateuserGoinginEvent,
});
} catch (err) {}
};
I think if its possible by aggregate but don't get what's best what to do this.
Try to use findOneAndUpdate if the event with _id does not already contain the user.
If that is the case, $push the new user:
const eventUserGoing = async (req, res) => {
try {
const updateuserGoinginEvent = await Events.findOneAndUpdate(
{ _id: req.body.eventid, userGoing: { $ne: req.user.user_id } },
{
$push: {
userGoing: req.user.user_id,
},
},
{
new: true,
}
);
res.status(200).json({
success: true,
message: 'Event saved successfully',
data: updateuserGoinginEvent,
});
} catch (err) {}
};

function returning before await function

im trying to write a function that updates shopping cart which given products info and give user the updated shopping cart, however when I call this function, database is updating but response is not.
Code
export const addToCart: Hapi.Lifecycle.Method = async (request, h, err) => {
const payload: ProductIdPayload = <ProductIdPayload>request.payload;
const userId: string = <string>request.auth.credentials._id;
try {
const [shoppingCart, product] = await Promise.all([
ShoppingCartModel.findOne({ userId: userId }),
ProductModel.findById(payload.productId),
]);
if (product) {
console.log(product);
if (shoppingCart) {
await shoppingCart.updateOne({
$push: { productIds: payload.productId },
$inc: { totalValue: product.price },
});
//above line updates database but below command returns non-updated shopping cart
return h.response({
shoppingCart: shoppingCart,
});
} else {
const newShoppingCart = new ShoppingCartModel({
userId: userId,
productIds: [payload.productId],
totalValue: product.price,
});
console.log(newShoppingCart)
await newShoppingCart.save();
return h.response({ shoppingCart: newShoppingCart });
}
} else {
const error = Boom.notFound("Product Not Found");
return error;
}
} catch (error) {
throw new Error();
}
};
Any idea why is this happening?
Try using:
const updatedShoppingCart = await shoppingCart.updateOne({
$push: { productIds: payload.productId },
$inc: { totalValue: product.price },
});
return h.response({
shoppingCart: updatedShoppingCart,
});
If the above solution doesn't work for you use findOneAndUpdate function on the Model and pass {new: true} in the options.

how to change username password using passport local mongoose

i'm trying to change the password of username using local mongoose
i tried to use setPassword function but it does not seem to work
router.put('/admin/users/:username', function(req,res){
User.findByUsername.then(function(sanitizedUser){
if (sanitizedUser){
sanitizedUser.setPassword(req.body.password, function(){
sanitizedUser.save();
res.redirect("back");
});
} else {
res.redirect("back");
}
},function(err){
console.error(err);
})
});
is there any other solution other than setpassword
what exactly i did wrong?
I have posted what I tend to do to reset password (part of it includes hashing it but the rest is the same). Except I am using async/await
const { password } = req.body;
let restP = new User();
try {
const newP = await restP.generateHash(password.password);
const resetP = await User.findByIdAndUpdate(
req.params.id,
{ $set: { passwordHash: newP } },
{
fields: { passwordHash: 0 },
new: true
}
)
// return image user object
res.send(resetP);
} catch (error) {
console.log(error);
return res.status(400).send(error);
}

Preventing duplicating entries with Mongoose and Node.Js

So I have a student grades object
[
{
_id: '5bf43c42a09e1129b8f0cd4c',
user: '5bc89dec5f6e1103f808671b',
StudentGrades: [
{
_id: '5bf43daf58f0f803d4e9760b',
classCode: 'ENG1A0',
gradeLevel: 12,
credit: 1,
mark: 67
}
],
__v: 0
}
];
I use the following backend code to make entries into the database
router.put('/:user_id', function(req, res) {
let id = req.params.user_id;
const gradeFields = {
classCode: req.body.classCode,
gradeLevel: req.body.gradeLevel,
credit: req.body.credit,
mark: req.body.mark
};
if (gradeFields)
passport.authenticate('jwt', { session: false }),
UserGrades.findOneAndUpdate(
{ user: id },
{ $push: { StudentGrades: gradeFields } },
{ new: true },
{ unique: true },
function(err) {
if (err) {
res.send(err);
} else {
res.send(gradeFields);
}
}
);
});
Everything is working but at this time, a person can have duplicate classes.
In the express code i tried using {unique: true} and tried setting the classCode mongoose model to unique as well, but it didn't work. Help would be appreciated
Validate that the user_id maps to an existing user.
Validate that this user does not already have a StudentGrade with the supplied classCode.
Update the document and return the updated user.
router.put('/:user_id', async (req, res) => {
const { user_id } = req.params;
const gradeFields = {
classCode: req.body.classCode,
gradeLevel: req.body.gradeLevel,
credit: req.body.credit,
mark: req.body.mark
};
try {
// Authenticate with Passport
await passport.authenticate('jwt', { session: false });
// Grab user with this user_id
const existingUser = await UserGrades.findOne({ user: user_id });
if(!existingUser) {
// If user does not exist, throw 404
res.status(404).send("User with this ID does not exist");
}
// Check if user has classCode already on an existing StudentGrade
if(existingUser.StudentGrades.some(sg => sg.classCode === req.body.classCode)) {
res.status(409).send("Student already has grade with this class code.");
}
// Update user record with new StudentGrade and return updates document
const updatedUser = await UserGrades.findOneAndUpdate(
{ user: user_id },
{ $push: { StudentGrades: gradeFields } },
{ new: true }
);
res.status(200).send(updatedUser);
} catch (e) {
console.log('Failed to update user grades', e);
// Unknown server error, send 500
res.status(500).send(e)
}
});

Resources