mongoose findByIdAndUpdate update objects and push other onto existing field - javascript

Hello I would like to update a document in my db using findByIdAndUpdate only doing minimal calls, but some values have to be pushed onto an array and other updated.
i'm sure there must be an easy way to make this into one route instead of using the two
router.put('/notes/:id', (req, res) => {
Player.findByIdAndUpdate({
_id: req.params.id
}, {
$push: {
notes: req.body.notes
}
}, {
new: true
})
.then(player => res.status(200).json(player))
.catch(err => res.status(400).json({
'err': 'updating went wrong'
}))
})
router.put('/:id', (req, res) => {
let updates = {};
if (req.body.first) {
updates.first = req.body.first;
}
if (req.body.last) {
updates.last = req.body.last;
}
if (req.body.school) {
updates.school = req.body.school;
}
if (req.body.rank) {
updates.rank = req.body.rank;
}
Player.findByIdAndUpdate({
_id: req.params.id
}, updates, {
new: true
})
.then(player => res.status(200).json(player))
.catch(err => res.status(400).json({
'err': 'updating went wrong'
}))
})

Related

MongoDB $set to update subarray, adding new entry instead of updating

im trying to update an oject in a sub-array and instead of replacing and updating the data. it adds a new enetry.
controller.js:
const updateSubCategory = asyncHandler(async (req, res) => {
const {
dataArray
} = req.body
const categories = await Category.find({})
if (categories) {
await Category.updateOne({
"SubCats._id": req.params.id
}, {
"$set": {
SubCats: {
name: dataArray[0],
image: dataArray[1]
}
}
}, {
"multi": true
})
res.json({
message: 'sub-category updated'
})
} else {
res.status(404)
throw new Error('Error')
}
})
I think you need this, but i am not sure, if you dont need this, if you can give sample data and expected output in json.
You can try an example PlayMongo
It updates the fields inside not replace all the embeded document (your query does that).
const updateSubCategory = asyncHandler(async (req, res) => {
const {
dataArray
} = req.body
const categories = await Category.find({})
if (categories) {
await Category.updateOne({
"SubCats._id": req.params.id
}, {
"$set": {
"SubCats.name" : dataArray[0],
"SubCats.image" : dataArray[1]
}
}
}, {
"multi": true
})
res.json({
message: 'sub-category updated'
})
} else {
res.status(404)
throw new Error('Error')
}
})

MongoDB/Mongoose $pull an Object in an Array where _id of the Object is matching

I have this Schema here
Consider the likedTours which is an Array of Objects (Tours) (ignore position 0).
I want to pull any Objects where the _id of a Tour matches the critiria.
Adding a new Tour upon liking a tour is okay, but on unlike I don't know how to pull that item out.
Here is my function in the Controller in the Node.JS backend
const unlikeTour = async (req, res) => {
try {
TourDB.Tour.findOneAndUpdate(
{ _id: req.params.tourid },
{
$pull: { likedUsers: req.userID },
$inc: { likes: -1 },
}
).exec(async (err, docs) => {
if (!err) {
try {
await UserDB.User.findOneAndUpdate(
{ _id: req.userID },
{ $pull: { 'likedTours._id': docs._id } } //Here I need help
).exec()
return res.status(200).send({ successMessage: 'Tour successfully unliked' })
} catch (err) {
return res.status(500).send({ errorMessage: 'User not found' })
}
} else {
return res.status(500).send({ errorMessage: 'Tour not found' })
}
})
} catch (err) {
return res.status(500).send({ errorMessage: err })
}
}
This method looks for a tour and update it by pulling out the userID and decrement the likes count by -1.
And then I try to find in the UserDB that tour in the likedTours and tried to pull but it doesn't not work like that.
Thanks in advance
you can update as
await UserDB.User.findOneAndUpdate(
{ _id: req.userID },
{ $pull: { likedTours: { _id: docs._id } } } //Here I need help
).exec();
reference: https://docs.mongodb.com/manual/reference/operator/update/pull/

RESTful API for HTTP DELETE doesnt check for null

Im currently writing a RESTful API for a webservice but im having trouble. Im trying to delete an mail, but first i want to check if the mail even exists. My problem is that it doesn't check if mail is null and doesn't respond with a 404. Im working with express and mongoose
router.delete('/:id', (req, res) => {
const { id } = req.params;
Mail.findById(id)
.exec()
.then((mail) => {
if (!mail) {
console.log(mail) // returns null
return res.status(404);
}
})
.then(
Mail.deleteOne({ _id: id })
.exec()
.then(() => {
res.status(200).json({
message: 'Mail deleted',
});
})
.catch((err) => {
res.status(500).json({ error: err });
})
);
});
I think you have to do the the deletion part of the code inside the first then block as an else statement. You are not returning anything that the next then block can use.
you could do:
Mail.findById(id)
.exec()
.then((mail) => {
if (!mail) {
console.log(mail) // returns null
return res.status(404).send() //need to send response;
}
Mail.deleteOne({ _id: id })
.exec()
.then(() => {
res.status(200).json({
message: 'Mail deleted',
});
})
}).catch((err) => {
res.status(500).json({ error: err });
})
PRO TIP: if you don't know it, learn async await. Code will look much cleaner!
Then it would look like this:
router.delete('/:id', async (req, res) => {
const { id } = req.params;
try {
const mail = await Mail.findById(id);
if(!mail) {
return res.status(404).send();
}
await Mail.deleteOne({_id: id});
res.status(200).json({
message: 'Mail deleted',
});
} catch(e) {
res.status(500).json({ error: err });
}

Part of the API is not working in NodeJS. How do I fix it?

I'm trying to build a REST API in NodeJS for an online-store. My code for the POST-request looks like this:
router.post('/', (req, res, next) => {
const order = new Order({
_id: new mongoose.Types.ObjectId(),
customer_name: req.body.order.customer_name,
total_price: req.body.order.total_price,
products: req.body.order.products,
});
order
.save()
.then(result => {
req.body.order.products.forEach(value => {
let availiableQuantity = value.available_quantity - value.ordered_quantity;
Product.findOneAndUpdate({ id: value.id }, { available_quantity: availiableQuantity
})
})
res.status(201).json({
message: "Successfully created product",
createdProduct: {
customer_name: result.customer_name,
products: result.products,
}
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
});
The issue that I'm having is that the code in .then block is not working when I'm trying to send this POST-request, even if I try to console.log something, it doesn't do anything, everything works except the code in .then block:
.then(result => {
console.log('test')
req.body.order.products.forEach(value => {
let availiableQuantity = value.available_quantity - value.ordered_quantity;
Product.findOneAndUpdate({ id: value.id }, { available_quantity: availiableQuantity
})
})
Am I missing something out?
You can instead use async await instead of processing the next step with the then block.
router.post('/',async (req, res) => {
try{
const order = new Order({
_id: new mongoose.Types.ObjectId(),
customer_name: req.body.order.customer_name,
total_price: req.body.order.total_price,
products: req.body.order.products,
});
var result = await order.save();
req.body.order.products.forEach(value => {
let availiableQuantity = value.available_quantity -
value.ordered_quantity;
Product.findOneAndUpdate({ id: value.id }, {
available_quantity: availiableQuantity
})
res.status(201).json({
message: "Successfully created product",
createdProduct: {
customer_name: result.customer_name,
products: result.products,
}
});
} catch(e) {
res.status(500).json({
message: "Bad request",
error: e
});
}
})

Cancel Promise.all update MongoDB when one reject

I have two Model: User and Project.
User: name, projects [ { id, role } ]
Project: name, members []
I wrote a function to add a member (from User) to Project. My code:
const addMember = async (req, res, next) => {
const { userId, role, projectId } = req.body
Promise.all([
Project.findByIdAndUpdate(projectId, { $push: {members: userId}}),
User.findByIdAndUpdate(userId, { $push: {projects: { id: userId, role: role}} })
]).then(values => {
if (!values[0] || !values[1]) return next("Can not find")
return res.json({
result: 'ok',
message: "Add member successfully!",
})
}).catch(error => next(error))
}
But it does not work as I expected. If projectId wrong, nested method 1 in Promise not working but nested method 2 still working, the database will be updated. The same as userId wrong.
How can I return error when once wrong?
If I am not wrong, you want to only update user when project update is successful, for that Promise.all is not the solution, chain the promises, like
Project.findByIdAndUpdate(projectId, { $push: {members: userId}})
.then(()=>{
return User.findByIdAndUpdate(userId, { $push: {projects: { id: userId, role: role}} });
})
.then(values => {
if (!values[0] || !values[1]) return next("Can not find")
return res.json({
result: 'ok',
message: "Add member successfully!",
})
}).catch(error => next(error))
Rather than calling findByIdAndUpdate functions in the
Promise.all block. You can split the code in to two parts.
1) Define findById function which only check if the record exists and an update function to update the entries
2) execute the findById and update codes in the Promise.all separately.
const addMember = async (req, res, next) => {
const { userId, role, projectId } = req.body
Promise.all([
Project.findById(projectId, { $push: {members: userId}}),
User.findById(userId, { $push: {projects: { id: userId, role: role}} })
]).then(values => {
if (!values[0] || !values[1]) return next("Can not find")
Promise.all([
Project.update(projectId, { $push: {members: userId}}),
User.update(userId, { $push: {projects: { id: userId, role: role}} })
]).then(values => {
return res.json({
result: 'ok',
message: "Add member successfully!",
})
})
}).catch(error => next(error))
}

Categories