How to use mongoose findAndUpdateOne() - node.js

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

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

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.

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