Cast to ObjectId failed for value "req.params.id" at path "_id" for model "Project" - node.js

I am trying to create a clone of employee management system. I want to implement a feature that when admin opens a details page for any project he will get list of available employees as checkboxes and when select them and submit then those employees will be added to the given project.
I am developing it using Node.js and MongoDB
My project schema is -
const ProjectSchema = new mongoose.Schema({
name: String,
deadline: Date,
description: String,
manager:{
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
},
employees: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "User"
}
],
created_on: {
type: Date,
default: Date.now
}
});
Form -
<form action="/admin/project/<%= project._id %>/addmembers" method="POST">
<div class="row">
<% employees.forEach((employee) => { %>
<% if(!employee.projects.includes(project._id)){ %>
<div class="col-12 col-sm-6 col-md-4 col-xl-3">
<input type="checkbox" value="<%= employee._id %>" name="newMembers"> <%= employee.name %> </input>
</div>
<% } %>
<% }); %>
</div>
<hr class="my-2">
<p class="lead">
<button class="btn btn-blue btn-lg">Add Members</button>
</p>
</form>
Code for handling the request -
router.post("/project/:id/addmembers", (req, res) => {
console.log("add member post route");
Project.findById(req.params.id, (err, foundProject) => {
if(err){
console.log(err);
req.flash("error", err.message);
res.redirect("back");
} else {
req.body.newMembers.forEach((employee) => {
foundProject.employees.push(employee);
})
foundProject.save()
console.log(foundProject);
req.flash("success", "Successfully added new members");
res.redirect("/admin/project/req.params.id");
}
})
});
Now whenever I submit form users are added but I always get an error Cast to ObjectId failed for value "req.params.id" at path "_id" for model "Project" instead of success message now I am new to mongo so I googled it but can't solve my problem can anyone explain me why this error is coming and how can I fix it?
Also I know that if if only one checkbox is selected then req.body.newMembers will not be array. If you can you provide better method to do it, it will be very helpful?
Update -
I also tried findOne(), find(), findByIdAndUpdate(), and id = mongoose.Types.ObjectId(req.params.id) but still get the same error message

It looks like what is happening is you aren't properly handling ids and _id. Given that you haven't mentioned anything, I assume you see this error only once. However, given that the error has to do with the project model/schema, and you use almost the same code for both manager and employees, the error should have to do with a difference between the two. The main difference I see is manager has id: {*id stuff*}, but employee has {*id stuff*} with no id:. However, I don't think this is the actual error, but just something to keep in mind. Try also changing the id type to something like number just to see if this is related to the issue.
What I think that actual error is is the fact that you use req.params.id in a findById(). This searches your database using the _id. First, having id and _id both is a bit redundant (if you have a reason, that's fine, but _id is something MongoDB needs, so it might be better to just stick with it as it is precreated and handled). Second, you are using a string/int as an id search. To test whether this is the issue, try changing findById() to something like findOne() or find(). Just to clarify, findById() doesn't explicitly need an ObjectId, so the type may not be the issue, but findById() does handle the search differently than find({_id: id}).
Another thing to check is that req.params.id actually gives the right value. It should, but this is something to verify. To do so, just console.log() it. If this is the problem, try moving :id to the end of the path.
In response to your edit:
Make sure that the problem doesn't have to do with not having id: in the employee (as stated above) and that it doesn't have to do with the id being a ObjectId rather than a number. If you change the id to a number, make sure to change the search so that it finds the object by id not _id. Just to let you know, every MongoDB object has an _id (even subobjects like employee and manager), so using id is somewhat redundant.
To give you more things to try: make sure you console.log() req.params.id to make sure it has the right value. Then, also try commenting sections of code until you find which line it is on. Try hardcoding some input until it works.

Related

Not being able to delete an item from to-do list using Item.removeOne( ) or Item.findByIdAndRemove( ) methods of mongoose in NodeJS

I am making a to-do list using mongodb,node.js,express and EJS. The part where I am stuck is I am not being able to delete and item from the list and the database. The idea is that on clicking a checkbox, the item beside will be deleted. Here is a layout for the same,
[https://i.stack.imgur.com/83gMW.png][1]
I made the necessary changes in my EJS file to create a "/delete" route as given below :
<%for(var i=0;i<taskslist.length;i++){%>
<form action="/delete" method="POST">
<div class="item">
<input type="checkbox" name="checkitem" value="<%= taskslist[i]._id %> " onChange="this.form.submit()">
<p><%= taskslist[i].activity %> </p>
</div>
</form>
<%}%>
In my app.js folder, I also made the necessary changes by using findByIdAndRemove( ) method for mongoose :
app.post("/delete", function (req, res) {
const delitem = req.body.checkitem;
Item.findByIdAndRemove(delitem, function (err) {
if (err) {
console.log("Error");
} else {
console.log("Succesfully deleted" + delitem);
res.redirect("/");
}
});
console.log(delitem);
});
However, the item is not getting deleted from the database and an error is showing in terminal, even though the console.log(delitem) is working and returning the id of the item whose checkbox is selected.
I am also giving a screenshot of the output I am getting at the terminal:
[https://i.stack.imgur.com/hGEkn.png][1]
All the methods related to adding items and creating database are working. I don't understand where the error is. Please help me out with this.

Method “simulate” is meant to be run on 1 node. 0 found instead. jest/enzyme

I even tried it by giving classnames and removing div and adding it back. Can somene help?
//Page1.js
<div className="email" >
<MyInput className="input1" name="email" type="email" onChange={formikProps.handleChange}/>
</div>
//Page1.test.js
describe("testing email",()=>{
test("email check",()=>{
let wrapper = shallow(<Page1/>)
wrapper.find('MyInput[name="email"]').simulate('onChange', {target: {
name: 'email',
value: 'ale#gmail.com'
}})
expect(wrapper.state('email')).toEqual('ale#gmail.com')
})
})
The first argument to simulate has to be the event name to be simulated not the name of the event handler.
wrapper.find('MyInput[name="email"]').simulate('change', {target: {
name: 'email', value: 'ale#gmail.com' }})
Shallow doesn't render child components. It will render just the react wrapper. For testing events and interactions, use mount. Also you can use console.log(wrapper.debug()) to see the content of wrapper. It will help you to identify the problem

How to label HTML for saving nested objects in Mongoose?

I have a model that looks like this:
const recipeSchema = new Schema({
title: { type: String , required: true},
description: { type: String , required: true},
steps:[{
text:{type:String},
ingredients:{type:String}
}]});
Using a bodyparser, I'm able to save data by simply tagging them in the name attribute of the HTML form. Like below:
<div class="input-field">
<textarea id="title" name="title" placeholder="Enter title here"></textarea>
<label for="title">Title</label>
</div>
This method works well for the first 2 fields (title and description), but I'm stuck on how to label them for the steps field. How would I make the code understand which input fields are for step.text and which are for steps.ingredient? And create an array of objects?
Figured it out. For anybody else who may stumble across this post, here's how you do it.
Basically you need to refer to the object in the array as (per the example above) in the following format:
step[0][text]
I couldn't find it anywhere in the documentation, but finally got it from this link:
http://www.thiscodeworks.com/how-to-save-input-from-html-form-to-json-file-using-body-parser-html-nodejs/5c44c4722178800014d5f127
How are you passing your data to the html page? I think using a view engine like EJS solves your problem better. It allows you to pass your data to a view, and then inject the data directly into your html elements.

How do I update a specific document from a form through mongoose?

Struggling with this problem because I'm missing some fundamentals I think, but after hours looking through the docs I think I need some help :)
I have a (simplified) collection as so:
const ExampleSchema= new Schema ({
Word: String,
Difficulty: String,
)};
Which I am succesfully displaying on a page as so:
<% ExampleSchemas.forEach(exampleschema=> { %>
<p><%= exampleschema.word %></p>
<p style="display: none" name="ExampleSchemaID" value="<%= ExampleSchema._id %>"</p>
<% }) %>
For each word I have a form below, I would like the user to be able to select easy, ok or hard and for this to set the value in the DB.
<form method="PUT">
<button formaction="/review/feedback/easy">Easy</button>
<button formaction="/review/feedback/ok">Ok</button>
<button formaction="/review/feedback/hard">Hard</button>
/form>
I have played around with a route like this to no avail
router.put("/review/feedback/easy", function (req,res){
var ID = req.body.ExampleSchemaID;
ExampleSchema.findByIdAndUpdate(
req.params.ExampleSchema._id,
req.Difficulty= easy);
The further issue is that I would like to display x number of these documents to the user, therefore I need a route that gets only that specific word.
router.put("/review/feedback/easy", function (req,res){
var ID = req.body.ExampleSchemaID;
ExampleSchema.findByIdAndUpdate({"_id": req.params.ExampleSchema._id},{"Difficulty": "3"});
but please not your difficulty is a number, so why not use a number instead:
const ExampleSchema= new Schema ({
Word: String,
Difficulty: Number,
)};
router.put("/review/feedback/easy", function (req,res){
var ID = req.body.ExampleSchemaID;
ExampleSchema.findByIdAndUpdate({"_id": req.params.ExampleSchema._id},{"Difficulty": 3});

Model is created but can't update with Express, Mongoose, and NodeJS

Alright so I'm having a problem with updating a model. I can create a Document and it works just fine but when I try to update, I get an error.
/Users/User/Sites/project/app.js:182
a.features.kids = req.body.a.features.kids;
^
TypeError: Cannot read property 'kids' of undefined
The model looks like this:
Affiliate = new Schema({
'name': String,
'address': String,
'features': {
'kids': { type: Boolean, default: false },
}
});
My form fields looks like this. They are used for both creating and updating with extra fields added for updating:
<input type="text" name="a[name]" id="a[name]" />
<input type="text" name="a[address]" id="a[address]" />
<input <% if (a.features.kids) { %>checked <% }; %>type="checkbox" name="a[features.kids]" id="a[features.kids]" />
Code for creating a new item. This works fine and all the information is added properly:
var a = new Affiliate(req.body.a);
a.save(function() {
res.redirect('/admin');
});
Broken code for updating an item:
Affiliate.findOne({ _id: req.params.id}, function(err, a) {
if (!a) return next(new NotFound('Affiliate not found'));
a.name = req.body.a.name;
a.address = req.body.a.address;
a.features.open_gym = req.body.a.features.kids;
a.save(function(err) {
res.redirect('/admin');
});
});
Yeah, I think the express bodyParser is probably not interpreting a[features.kids] the way you expect. You can access the field with req.body.a['features.kids'] since it's not interpreting that embedded period. Try naming your <input> a[features][kids] and see if that parses into the object structure you are expecting.

Resources