How to update document in MongoDB through Mongoose - node.js

I am trying to update my document field with the following code, but I catch an error "Cannot GET /updation".
My code:
router.put('/updation', (req, res) => {
const query = { email: "babra#arzepak.com" };
const newEmail = { $set: { name: "babra", email: "nadralatif952#gmail.com" } };
Registration.updateOne()
.then((registration) => {
console.log("updating");
res.render('index', { title: 'updating registrations', registrations });
})
.catch(() => {
res.send('Sorry! Something went wrong.');
});
});

send a request with PUT method and you didn't use of query and newEmail as arguments for updateOne() pass them, and in new version of mongoose you don't need to $set for updating so change your code like this :
router.put('/updation', (req, res) => {
const query = { email: "babra#arzepak.com" }
const newEmail = { name: "babra", email: "nadralatif952#gmail.com" }
Registration.updateOne(query,newEmail)
.then((registration) => {
console.log("updating")
res.render('index', { title: 'updating registrations', registrations });
})
.catch(() => { res.send('Sorry! Something went wrong.'); });
})

Wrong Method
In your router you registered a route '/updation' for PUT method.
Hence only request with method PUT will be handled by your router. The error Cannot GET /updation means you are trying to handle a request with GET method which is simply not registered by your router.
A - If this code is supposed to get triggered when you visit the page via browser, then you should register the route for GET method, like router.get('/updation', ... ),
or
B - If this code is supposed to run seperate from your view (like a REST API should), then use a PUT request and end the request inside your router with res.status(200).json(yourdata)
📑 Sidenote :
It looks like you did not completely setup your mongoose query, I mean you defined the query but you don't use it in the database request. To use the defined query you propbably should change your code, according to the mongoose docs : https://mongoosejs.com/docs/api/model.html#model_Model.updateOne . I am not including a specific code example here, since it's not part of the question.

Related

NOT WORKING: Mongoose findByIdAndUpdate() does not work

I am trying to create a (MERN stack) management system that keeps track of vacant rooms in a hotel.
I am trying to change the roomTypeAOccupiedTotal from 2 to 3.
From the client side, it sends an axios.put()request as follows:
axios
.put(`http://localhost:8082/api/myHotel/${branchStatus.id}`, data)
this is the server-side code:
router.put('/:_id', (req, res) => {
/*
req.params looks like this:
{ _id: '63b4d533fabbf31cdb519896' }
req.body looks like this:
roomOccupied5F: 3,
roomOccupied6F: 5,
roomTypeAOccupiedTotal: 2,
roomTypeBOccupiedTotal: 8,
*/
let filter = { _id: mongoose.Types.ObjectId(req.params._id) }
let update = { $set: req.body }
MyHotel.findByIdAndUpdate(filter, update, {new: true})
.then(data => res.json({ msg: 'updated successfully' }))
.catch(err =>
res.status(400).json({ error: 'Unable to update the Database' })
);
Below are the GET request and PUT request sent using POSTMAN.
after the message "updated successfully", I sent another GET request to check, but there are no changes to the variable(roomTypeAOccupiedTotal).
Could someone help me with solving this problem? the findByIdAndUpdate() method is working, as its not throwing any errors, but its not updating.
I believe your problem is the filter object. Looking at the docs for findByIdAndUpdate, it expects to receive the id param, not a filter object.
https://mongoosejs.com/docs/api/model.html#model_Model-findByIdAndUpdate
Parameters:
id «Object|Number|String» value of _id to query by
Additionally, when you create an objectId out of the request param, you aren't creating a new instance of it, so whatever was passed in would have failed to match anything. My IDE highlights this for me:
Your fix is likely something like this:
const id = new mongoose.Types.ObjectId(req.params._id)
MyHotel.findByIdAndUpdate(id, update, {new: true})
No need to convert id, and no need to use the update operator(i.e. $set).
try this:
MyHotel.findByIdAndUpdate(req.params._id, req.body, { new: true }, (err, hotel) => {
if (err) {
console.log(err);
} else {
console.log(hotel);
}
});

Deleting object from mongoose database not working if site is not refreshed

app.delete("/api/persons/:id", (req, res, next) => {
Person.findByIdAndDelete(req.params.id)
.then((result) => {
res.status(204).end();
})
.catch((error) => next(error));
});
Not sure how to even explain this properly, but there is my delete method. It works fine for objects that are allready in the databases, but if I add a new one and I dont refresh the site, I get error: Cast to ObjectId failed for value "undefined" (type string) at path "_id" for model "Person"
Below is my mongoose schema if that helps:
const personSchema = new mongoose.Schema({
name: { type: String, required: true },
number: { type: Number, required: true },
});
personSchema.set("toJSON", {
transform: (document, returnedObject) => {
returnedObject.id = returnedObject._id.toString();
delete returnedObject._id;
delete returnedObject.__v;
},
});
My guess is you're optimistically updating your frontend with the new Person without waiting for a successful DB response with the new data. That is a valid technique, but gets you into trouble if you're not careful.
My suggestion would be to also send the new value from the database back to your app right away say it can stay in sync. You likely have no _id value on the front end if you're optimistically updating the app before a DB response.
Something like this:
app.post("api/person/new", async (req, res) => {
try {
const person = new Person(req.body)
await person.save()
res.status(201).send({ person })
} catch (err) {
res.status(500).send({ err })
}
})
And then more importantly, your API handler on the frontend needs to take that returned person value and use it to update the values on your front end, so it has access to the _id property for immediate deletion. And if there's an error creating the person for any reason, you can remove the person from the front end, or handle it however you wish.
I don't know what your app is built with, so I can write a sample bit of code for it.

Update data in MongoDB using Mongoose and Node.js

I am trying to update certain info in a user collection, when the user is visiting a page.
But my method doesn't work. Can anyone help to get it fixed.
app.get('/add-your-accommodation/apartment-type', (req, res, next) => {
if (req.isAuthenticated()) {
res.render('apartment-type.ejs')
} else {
res.render('login.ejs')
}
var id = req.params.id
if(mongoose.Types.ObjectId.isValid(id)) {
User.findByIdAndUpdate(id, {$set: {accomtype: 'house'}},{new: true})
}
});
Your req.params.id is undefined since there is no mention of it in the route path. You can do this,
app.get('/add-your-accommodation/apartment-type', (req, res) => {
if (!req.isAuthenticated()) {
return res.render('login.ejs')
}
res.render('apartment-type.ejs')
var id = req.user._id //since you're using passport (LocalStrategy)
if(mongoose.Types.ObjectId.isValid(id)) {
User.findByIdAndUpdate(id, {$set: {accomtype: 'house'}})
}
})
Now when you call your API, do it like this,
GET /add-your-accommodation/apartment-type
I agree with #kedar-sedai, when you update/change something in your DB, you should not use a GET request. A good practise would be to use the PUT method, even if you have nothing to pass in the body. It makes it easier for you and other developers to understand what your code does at a glance.
Here are 4 HTTP requests that will work in most of the use cases :
GET
You want to retrieve information from your DB (ex: get users, get all the apartment types...)
POST
You want to add information (ex: register user, add an apartment, ...), or send information using the body of the POST request (ex: login, ...)
PUT
You want to update a value (ex: change username, change an apartment type, ...)
DELETE
You simply want to delete something in your DB (ex: delete a user...)
Try findOneAndUpdate. Also, use callback in your query function for getting the error or result.
app.get('/add-your-accommodation/apartment-type/:id', (req, res, next) => {
if (req.isAuthenticated()) {
res.render('apartment-type.ejs')
} else {
res.render('login.ejs')
}
var id = req.params.id
if(mongoose.Types.ObjectId.isValid(id)) {
User.findOneAndUpdate({_id: mongoose.Types.ObjectId(id)}, { $set: { accomtype:'house' } },(err, result)=>{
if (err) throw new Error(err);
console.log(result)
return
})
}
});

Sequelize - Creating Multiple Tables Using Id of First Table Created

I'm doing a project using Express, & Sequelize and have run into an issue:
I'm trying to create an api route that, on a button click, will create a row in my 'member' & 'memberinstrument' tables. Those tables have an association in my models that: member 'hasMany' memberinstruments & memberinstruments 'belongsTo' member.
This is what I have right now:
router.post("/api/individual/signup", async (req, res) => {
try {
const member = await db.Member.create({
memberName: req.body.memberName,
location: `${req.body.city}, ${req.body.state}`,
profilePicture: req.body.profilePicture,
UserId: req.user.id
})
const memberInstrument = await db.MemberInstrument.create({
instrument: req.body.instrument,
MemberId: member.id
});
res.json({ member, memberInstrument });
} catch (error) {
console.log(error.message);
res.status(500).send('Sever Error');
}
})
I'm testing it out in postman and it simply says I have a 'server error' (which doesn't happen if I delete the whole memberInstrument posting section) and in node I get "Cannot read property 'id' of undefined". I know it must have something to do with the timing of trying to create member, and then trying to get that member id for memberinstrument, but I can't figure out how to resolve this.
Any help would be much appreciated!
(edit:
I commented out both UserId & MemberId and it successfully posts.
uncommenting just UserId creates the same error:
UserId is a nullable field so I don't know why it's doing a server error if I don't define it (or maybe I have to define it as null but I do not know how to do that in postman since it's coming from .user instead of .body
uncommenting just MemberId creates the same error)
Since I'm doing this in Postman, and don't know how to send a req.body with that, I was getting that id error. I changed req.user.id to req.body.id which will be populated with information from a front end state and it is now working correctly.
I think it's unnecessary for you to include all the fields in your .create()
try this
router.post("/api/individual/signup", async (req, res) => {
try {
const data = req.body;
const member = await db.Member.create(data);
const [registration, created] = member;
if(created){
//insert more of your code here on creating **MemberInstrument**, this is just a sample.
await db.MemberInstrument.create(registration.member_id);
}
res.json({
registration,
created
});
} catch (error) {
console.log(error);
res.status(500);
}
}
On your postman request, you will input the body or fields in json format, except the ID, IDs should not be included on the postman body.

expressjs: Best way to handle multiple optional route params

I'm using nodejs Express. I would like to have a router that receive id or username as request param as below:
router.get('/:id?/:username?', authMiddleware, function (req, res, next) {
models
.User
.findAll({
where: {
$or: {
id: req.params['id'],
username: req.params['username']
}
}
})
.then(function (rows) {
res.send(rows);
})
}
However, express seems to not understand my request on:
http://localhost:3000/api/1.0/users//david
Which I would like to query user by username instead of id
The only way works right now is defining a route as: /:id_or_username as below:
router.get('/:id_or_username', function (req, res, next) {
models
.User
.findAll({
where: {
$or: {
id: req.params['id_or_username'],
username: req.params['id_or_username']
}
}
})
.then(function (rows) {
res.send(rows);
})
}
But it is kind of dirty and I'm not happy with that code.
Is that possible to define router in this case using REST style instead of :idOrName param?
Assuming your id is an int, you can do something like this:
router.get('/:id_or_username', function (req, res, next) {
var where = {}
var param = req.params['id_or_username']
if (isNaN(param)) {
where.username = param
} else {
where.id = param
}
models.User.findAll({where}).then(function (rows) {
res.send(rows)
})
}
Now you can send the id or the username using the same paramether
I am not sure how your system is setup but this sounds like a better use for a req.query instead of req.param.
You should use req.query when you are not sure what the input might be, and use req.param when passing information you are sure will be there. There is probably a way to do this with req.param but I am not sure I can think of a reason why you'd want to do it that way.
This way you could do an action like:
action = "/users/"+ id ? id : username
and then req.query for it.

Resources