function returning before await function - node.js

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.

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()

How to use populate on saving new data on mongoose

Hello their I am trying to populate postedBy field on creating a new comment.
When i create a comment i save it on mongodb and also I save comment._id on my feature model (as objectId)
then i am sending res.json(comment)
Can i populate before sending json response?
I also tried but nothing happened
My code-
exports.createComment = async (req, res) => {
console.log("run?");
const { featureId } = req.params;
const { content } = req.body;
const postedBy = req.auth._id;
if (!content) {
return res
.status(400)
.send({ error: "Please provide a content with your comment." });
}
const comment = new Comment({
content,
postedBy,
});
await comment.save();
await comment.populate("postedBy", "_id username");
Feature.findByIdAndUpdate(
featureId,
{ $push: { comments: comment._id } },
{ new: true }
).exec((err, result) => {
if (err) {
return res.json({
error: errorHandler(err),
});
}
});
return res.json(comment);
};```
exports.createComment = async (req, res) => {
console.log("run?");
const { featureId } = req.params;
const { content } = req.body;
const postedBy = req.auth._id;
if (!content) {
return res
.status(400)
.send({ error: "Please provide a content with your comment." });
}
const comment = new Comment({
content,
postedBy,
});
await comment.save();
// One of the ways that I use.
let populatedData= await Comment.findById(comment._id).populate("postedBy", "_id username");
console.log(populatedData)
Feature.findByIdAndUpdate(
featureId,
{ $push: { comments: comment._id } },
{ new: true }
).exec((err, result) => {
if (err) {
return res.json({
error: errorHandler(err),
});
}
});
return res.json(comment);
};

Mongoose How to await updating documents?

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)
}
}

NodeJS does not returning status code but changes database

my code below works just fine and updates or creates documents, but does not return status code 200 it just waits without any return value, any idea why this is happening
exports.flagUser = async (req, res) => {
try {
const user = await FlaggedUser.findOne({ userId: req.body.userId });
if (user) {
if (user.flaggedBy.includes(req.body.flaggedBy.toString())) {
print("error");
return res.status(500);
} else {
console.log("user found");
await user.updateOne({
$inc: { flagCount: 1 },
$addToSet: { flaggedBy: req.body.flaggedBy },
});
return res.status(200);
}
} else {
const flaggedUser = new FlaggedUser({
_id: new mongoose.Types.ObjectId(),
userId: req.body.userId,
flagCount: 1,
flaggedBy: [req.body.flaggedBy],
});
await flaggedUser.save();
console.log("flag");
return res.status(200);
}
} catch (error) {
console.log(error);
return res.status(500).json({
...error,
});
}
};
If you want to send just status codes you need to write res.status(num).send(); or res.status(num).end();. Here is the doc to read more up on this http://expressjs.com/en/api.html

How to use mongoose findAndUpdateOne()

i am trying to update mongoDB via mongoose using the findOneAndUpdate() method,
i destructure my fields from req.body but if i updated only a single value others are set to null, how do i fix that
CODE
const { name, email, phone, type } = req.body;
await Contact.findOneAndUpdate(
{ _id: req.params.id },
{ $set: { name, email, type, phone } },
{ upsert: true },
(err, updatedContact) => {
if (err) {
console.error(err.message);
res.status(400).send('Could not updat');
} else {
res.json(updatedContact);
}
}
);
});
******************************************
This gives me the desirable result i expected please not that i have not implemented error checking you can do that using the 'express-validator'
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { name, email, phone, type } = req.body;
// Build contact object
const updatedContact = {};
if (name) updatedContact.name = name;
if (email) updatedContact.email = email;
if (phone) updatedContact.phone = phone;
if (type) updatedContact.type = type;
try {
await Contact.findOneAndUpdate(
{ _id: req.params.id },
{ $set: updatedContact },
{ new: true }
);
res.json(updatedContact);
} catch (err) {
console.error(err.message);
res.status(400).send('Could not update');
}
});

Resources