Why is findByIdAndUpdate() not updating an _id's information? (using $set) - node.js

I'm a beginner in MongoDB and have been following a tutorial from one year ago. I send a PUT request with the following json:
{
"username": "NoMore"
}
Then I use findByIdAndUpdate() with the _id being pulled from the url's :id params. The function is async, but await is used on the update function. Despite the code seeming to have worked one year ago, I can not find any updated information regarding this online.
My entire function is as follows:
router.put('/:id', verifyTokenAndAuthorization, async (req, res) => {
if (req.body.password) {
req.body.password = CryptoJS.AES.encrypt(
req.body.password,
process.env.PASS_SEC
).toString();
}
try {
const updatedUser = await User.findByIdAndUpdate(
req.params.id,
{
$set: req.body,
},
{ new: true },
);
res.status(200).json(updatedUser);
} catch(err) {
res.status(500).json(err);
}
})
I have tried setting the _id manually as a string, but the code still went to an error 500. I also preset the req.body which did not change the result.
I am expecting for the user's username to become the username sent in the PUT request.

I didn't import the model (User) so there was no connection to MongoDB.
I put the following code at the top:
const User = require('../models/User');
Now it works fine.

Related

How to save cloudinary url to mongoDb

I'm trying to save Cloudinary url to MongoDB but really don't know what is wrong with my code, because it's not working.
here is my code :
exports.test = asyncHandler(async (req, res, next) => {
const email = req.params.email;
console.log
cloudinary.uploader
.upload(req.file.path, { folder: 'avatar' })
.then((result) => {
console.log(result);// shows correctly on console
const { secure_url, public_id } = result;
console.log('url:',secure_url)// url & secure_url shows correctly on console
console.log('public_url:',public_id);
Resume.findOneAndUpdate(
{
email:email,
},
{ $set: { imagePath: secure_url} },
{
new: true,
fields: {
imagePath: 1,
},
}
);
console.log('upload successful!!');
})
.catch((error) => {
console.log(error);
});
});
I use $set because I want the field created if it didn't exist before. Also, I get the public_id and secure_url successfully from Cloudinary, but it didn't save in my database.
here is the output from console.log(result):
{
asset_id: '1ee919b68e258c9778097e40671ac710',
public_id: 'seawedkarowxgnipz8hq',
url: 'http://res.cloudinary.com/workaman/image/upload/v1656322947/seawedkarowxgnipz8hq.png',
secure_url: 'https://res.cloudinary.com/workaman/image/upload/v1656322947/seawedkarowxgnipz8hq.png',
original_filename: 'file_cuyajt',
}
and here is how i defined the model:
const ResumeSchema = new mongoose.Schema({
imagePath:{
type:String,
required:false
},
cloudinary_Id:{
type:String,
required:false
},
})
It seems I'm missing out on something but I really can't figure it out. when I submit from the frontend, I get the message "console.log('upload successfully!!')" but nothing is saved.
I think the issue here is that you're mixing up the MongoDB Node.js SDK with Mongoose a little bit. In the code that you shared you have both ResumeSchema and Resume - just check that those are correct.
In Mongoose the findOneAndUpdate() method does not have a $set option. The MongoDB CLI and subsequently their Node.js Driver also has findOneAndUpdate(), but the signature of that function and it's usage options somewhat differ.
Without seeing the rest of your code it's hard to tell what is exactly going on but my gut feeling is that you've mixed up these two methods. I hope this helps.

How to fix querying issues with mongoose and express [duplicate]

This question already has answers here:
Can't find documents searching by ObjectId using Mongoose
(3 answers)
Closed 1 year ago.
I am still fairly new to dynamic routing and although it makes sense, I am having issue implementing it correctly. Below is a function I want to grab the user's purchases from the database and export it as a csv. I had it working on local mongoDB but when I moved to Atlas for hosting, it only grabs the first person listed in the database and not the person logged in. Could I get some guidance on why my req.params is not working. Thank you in advance.
(This route would fall under app.use(/profile, profile) in the server)
profile.js
// DOWNLOADING CSV OF PURCHASES
router.get("/purchased-items/:id", csvAbuseLimiter, (req, res) => {
if (req.isAuthenticated()) {
User.findOne({ id: req.query.id }, (err, foundUser) => {
if (foundUser) {
console.log(foundUser);
const userPurchases = foundUser.purchases;
const fields = ["name", "order", "duration", "asset"];
const json2cvsParser = new Parser({ fields });
try {
const csv = json2cvsParser.parse(userPurchases);
res.attachment(`${req.user.username}-purchases.csv`);
res.status(200).send(csv);
req.flash("success", "successful download");
} catch (error) {
console.log("error:", error.message);
res.status(500).send(error.message);
}
}
});
}
});
person logged in
What the route is pulling.
In the code provided you are using req.query.id and not req.params.id

Update record based on username given in Request body

I need to update value in Group db Group_name to the value send in Json payload.
Db schema
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
username: String,
Group_name: {
type: String,
default: '',
}
});
mongoose.model('User', UserSchema);
And API request
router.put('/join', async(req, res) => {
try {
const data = await User.updateOne(req.params.username, {
Group_name: req.body.Group_name
});
console.log(data)
res.send({ msg: "Group Updated!!!" })
} catch (err) {
console.error(err.message);
res.sendStatus(400).send('Server Error');
}
});
currently its updating only first record which is incorrect , my requirement is to check for all records based on username given and according to username given in request parameters ,i will update value of Group_name to the value sent in request body.
can anyone help me ?
Modify query condition.
const data = await User.updateOne(
{ username: req.params.username },
{ $set: { Group_name: req.body.Group_name } }
);
First of all, understand the difference between req.body & req.params
req.body means hidden parameters sent in request body like in post or put requests.
req.params means defined paramters in URL. For this, you must have it defined in your route like below
router.put('/join/:username', async (req, res) => {
// ^^^^^^^^ here it is defined, now you can access it like
const username = req.params.username;
//or
const {username} = req.params; // destructuring
}
there is one more thing and that is
req.query means undefined paramters attached to URL with ?/&
If you want to give username without pre defining like /join?username=john then use req.query
router.put('/join', async (req, res) => {
const {username} = req.query;
}
Then you should use updateMany() function instead of updateOne()
try {
const {username} = req.params;
const {Group_name} = req.body;
const data = await User.updateMany(
{username}, // find as many users where username matches
{Group_name} // update group name from body
);
console.log(data);
The consoled data would be like { n: 2, nModified: 2, ...} because the update queries don't return updated documents but status of the query. If you want to get updated record set, you have to query again with find().
// after update
const updatedRecord = await User.find({ username });
console.log(updatedRecord);
::POSTMAN::
Postman has two types of parameters
Params
Body
If you add in Params it will be added in URL /join?username=john#email.com&Group_name=GroupB and you have to access it in code with req.query.username or req.query.Group_name
If you add in Body it will be hidden and can be accessed with req.body.Group_name etc
Hope it helps!

Mongoose not saving record after array is updated

I've seen a couple similar posts, but I can't get anything to work. The following is for a podcast episode topic suggestion app. It's meant to upvote a topic by adding a user ID to an array of user IDs saved to the topic object. Everything seems like it works, but topic.save() isn't actually saving.
router.post('/upvote/:id', auth, async (req, res) => {
try{
var topic = await Topic.findById(req.params.id);
const reqId = req.body._id;
if(topic.upvotes.includes(reqId)){
res.status(409).send('Topic already upvoted.');
}
console.log(`pre-update: ${topic}`);
topic.set({
upvotes: topic.upvotes.push(reqId)
});
console.log(`post-update: ${topic}`);
try{
//topic.markModified('topic.upvotes');
topic = await topic.save();
res.status(201).send(topic);
} catch{
next();
};
} catch{
res.status(404).send('Topic with given ID not found.');
};
});
I tried a few different variations on topic.markModified() because I saw that suggested on other posts, but nothing worked.
Here's what those two console.log()s show:
pre-update: {
upvotes: [],
_id: 612d701dd6bbfd3c5c36c906,
name: 'a topic',
description: 'is described',
category: 61217a75f30c6c826af9076b,
__v: 0
}
post-update: {
upvotes: [ 612996b46f21d2086c9d4d52 ],
_id: 612d701dd6bbfd3c5c36c906,
name: 'a topic',
description: 'is described',
category: 61217a75f30c6c826af9076b,
__v: 0
}
These look like it should work perfectly.
The 404 response at the very end is what's actually getting sent when I try this. I'm using express-async-errors & if the next() in the nested catch block was getting called, it would send 500.
Any suggestions?
I am actually not sure what exactly your trying to do. If you want to add a new value to a field only at a particular place then put or patch is to be used not post. post will update the whole document. and patch put is for partial updation.
Can you refer the sample code which I have given, hope that would be helpful for you in one or the other way.
router.put("/:id", [auth, validateObjectId], async (req, res) => {
const { error } = validateMovie(req.body);
if (error) {
return res.status(400).send(error.details[0].message);
}
let genre = await Genre.findById(req.body.genreId);
console.log(genre);
if (!genre) {
return res.status(400).send("No genre found with given id");
}
let movieDetails = await Movie.findByIdAndUpdate(
req.params.id,
{
title: req.body.title,
numberInStock: req.body.numberInStock,
dailyRentalRate: req.body.dailyRentalRate,
liked: req.body.liked,
genre: {
_id: genre.id,
name: genre.name,
},
}, //when using patch method, then you need not have to write this whole thing. instead just write req.body
{ new: true }
);
if (!movieDetails) {
return res.status(404).send("No such movie details found.");
}
res.send(movieDetails);
});
I figured it out. I think mongoose doesn't like it if you try to push() a new element like a normal array.
I used addToSet() instead and it worked.
https://mongoosejs.com/docs/api/array.html#mongoosearray_MongooseArray-addToSet

Req.body returns undefined : ExpressJs, NodeJs

Please help me I'm having this error for 5 days.
I'm trying to delete data inside of my array on MongoDB
but my req.body returns undefined even though I have my body-parser. I'm using axios.patch for request.
It works well in my postman but once I sent data that's where the problem occurs.
Here's my axios api call.
export const deleteTask = (id,post) => api.patch(`/main/${id}`, post);
Here's my schema.
const todoSchema = mongoose.Schema({
username: {
type: String,
},
password: {
type: String,
},
task: [String],
time: {
type: Date,
default: Date.now,
}
});
const TodoModels = mongoose.model('TodoModels', todoSchema);
here's my query.
export const deleteTask = async (req,res) => {
const { id } = req.params;
console.log(req.body);
if(!mongoose.Types.ObjectId.isValid(id))
return res.status(404).json(`Invalid ID`);
await TodoModels.findByIdAndUpdate(id,{$pull:{ task: req.body.task }},{
new: true });
}
My req.body has no task and I don't know why. Once I send data it returns undefined but the ID from req.params is not undefined.
Also once I sent the data from client to backend/server req.body returns this { data: '' } the data I sent became the element. I believe it was supposed to be { task: 'data' }
If your deleting a record then why are you using findByIdAndUpdate ; it should be findByIdAndDelete. I have put a sample code you to refer. There are 2ways you can delete a record. You can try them out and see.
Way 1:
router.delete('/:id', [auth, admin, validateObjectId], async(req, res) => {
//check for existing genre
const movieGenre = await Genre.findByIdAndDelete(req.params.id);
if (!movieGenre) {
return res.status(404).send('No such movie genre found with given id.');
}
res.send(movieGenre);
})
Way 2:
router.delete('/:id', [auth, admin, validateObjectId], async(req, res) => {
//second way to delete
let movieGenre = await Genre.findById(req.params.id);
if (!movieGenre) {
return res.status(404).send('No such movie genre found with given id.');
}
await movieGenre.deleteOne();
const index = genres.indexOf(movieGenre);
genres.splice(index, 1);
res.send(movieGenre);
})
Hope the answer helps you in any way.

Resources