trying to pass check boxes as string (node) - node.js

im doing a small project to learn fullstack (mongo&node&express&ejs), what i have in the project:
-object - name film. it got a couple of fields, like length, genre, director.
-an add film form.
i store the objects in mongo. overall everything is working good.
in the add film, the genre label is an options one - and i decided it would be more professional to make it check boxes, so user can choose how many genres as he want (after all most films are belong to a couple of genres.) i need one of the 2 next options:
-to change the genre field type of the object from string to array, and store an array of all the select check boxes, and show them in the film page. (i didnt manage to achieve an array of all the selected check boxes name)
-leave the genre field type as string, and then just display it as string. (didnt work so far, gets blank)
right now when its just options, it get passed as string, and all is working good and really simple. but i cant manage to work with the check boxes so far. tried as array and as String and so far all errors or undefined. i looked alot of solutions and all i saw are solutions in php or solutions that require document property (which doesnt work, from googling i understood its because of node.)
any idea how can i implement such thing?
this is what i have now (genre as options, and its working):
the object (not all the fields)
const filmSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
description: {
type: String,
required: true
},
releaseYear: {
type: Number,
required: true
},
genre: {
type: String,
required: true
},
#the form genre part
<label>Genre</label>
<select name="genre">
<% genre.forEach(g => { %>
<% if (g === film.genre) { %>
<option selected label="<%= g %>" value="<%= g %>"></option>
<% } else { %>
<option value="<%= g %>"><%= g %></option>
<% } %>
<% }) %>
</select>
the post (relevant parts)
router.post('/', async (req, res) => {
const film = new Film({
title: req.body.title,
director: req.body.director,
releaseYear: req.body.releaseYear,
genre: req.body.genre,
length: req.body.length,
description: req.body.description,
})
displaying a film
<h2> <%= film.title %> </h2>
<img height="150" width="100" src="<%= film.posterImagePath %>">
<div>Director: <%= film.director.name %></div>
<div>Release Year: <%= film.releaseYear %> </div>
<div>Genre: <%= film.genre %> </div>
<div>Length: <%= film.length %></div>
<div>Description: <%= film.description %></div>
im stuck on this problem for a few hours, any help would be greatly appreciated!

Related

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

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.

How to change from false to true with checkbox input?

If somebody can help me. I want to do next thing.With check box I want to choose which post to put on index page
This is my schema
var foodSchema = new mongoose.Schema({
title:String,
image:String,
text:String,
video:String,
checkBox:{type:Boolean, default:false},
created:{type: Date, default:Date.now},
comments:[{
type: mongoose.Schema.Types.ObjectId,
ref:"comment"
}
]
});
This is my new.ejs file
<spam class="hederSpam">
<input type="checkbox" name="checked" value="true">
post
</spam>
```
here i wanna to display
``` <%newFood.forEach(function(check){ %>
<%if(check.checkBox===true){%>
<h3 class="indexh2"><%= check.title %></h3>
<%= check.checkBox%>
<a href="/food/<%= check._id%> " >Read More</a>
<% })%>
and in site.js file I trying to do this but every time gives me false..
food.create(req.body.foodForm, function(err, postFood){
var n = req.body.checked;
if(err){
console.log("err")
}else{
if( n == "true"){
food.checkBox=true;
}
res.redirect("/food");
}
})
});
This seems strange piece of code:
console.log("err)
Also there should be space where I put underscore here:
name="checked"_value="true"

Iterate through a MongoDB object's data

I will start off with how my mongoDB data looks like:
_id : 5c5b450918cb2b121648ff7a
name : "dannondarko"
email : "dangilmail#gmail.com"
password : "$2a$10$3z5m1e9Pcfid72Q2GchCjeTD55/SsIxmtWr3I1ZiA.DX/KlpfTbdK"
date : 2019-02-06 20:35:21.973
__v : 0
posts : Array
0 : Object
note : "test for the user dannondarko"
date : "02/08/2019"
This is just a side project and most likely will never be live so don't worry about the security of me posting this data! As for how I am procession the code in my server code:
app.get('/:username', (req, res) => {
username = req.params.username.toLowerCase();
const collection = req.app.locals.collection;
collection.find({ name: username }).toArray(function (err, results) {
if (err) {
res.status(500).send("Error communicating with the DB.");
} else if (results.length > 0) {
console.log("Here are the results: " + results);
console.log({people: results});
res.status(200).render('profile', {posts: results, name: username});
} else {
next();
}
});
});
What I am doing with this code is say you head to the address bar '/dannondarko', it should find 'dannondarko' in the collection, which it does fine, and then the 'results' variable is the complete object that I posted above. What I am trying to do is just get the 'posts' data, such as the note and date.
The note and date is the only data I need, which will be sent to this .ejs file that should create a post (kind of like FB) that shows the users' notes and date of the post. Here is my .ejs file:
<h1 class="mt-4"><%= name %></h1>
<div class="container">
<br>
<% for(var i=0; i < posts.length; i++) { %>
<div class="container">
<label><%= posts[i].note %></label>
<div class="container">
<label><%= posts[i].date %></label>
</div>
</div>
<% } %>
</div>
I hope that's enough information. I believe my downfall is not knowing how to just extract the 'posts' array from MongoDB from a certain user and iterate through the objects and sending over the note and date to the .ejs.
The results is an array of documents and you render this array to ejs as posts. Now in your ejs file posts represent the array of documents, not the posts array. So if you want to loop through all results you should edit your code like this:
<% posts.forEach(post => { %>
<h1 class="mt-4"><%= post.name %></h1>
<div class="container">
<br>
<% post.posts.forEach(p => { %>
<div class="container">
<label><%= p.note %></label>
<div class="container">
<label><%= p.date %></label>
</div>
</div>
<% }) %>
</div>
<% }) %>
If i understand well your mongo model structure the above should help you.

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

Express with mongodb find one

Im new to nodejs , express and mongodb.
I got stuck at the findOne function using ObjectId of mongodb
With the code below, I got the error : "Error: Argument passed in must be a single String of 12 bytes or a string of 24 hex characters"
Im using lastest version of everything (because Im new to them)
My code in view:
<% for(var i = 0 ; i < posts.length; i++ ) { %>
<% post = posts[i] %>
<article class="post">
<div class="post-preview col-xs-10 no-gutter">
<h2>
<a href="/posts/<%=i%>">
<%= post.title %>
</a>
</h2>
<p><%= post.description %></p>
<p class="meta">
<%= post.author.name %> in
<%= post.category.name %> <i class="link-spacer"></i> <i class="fa fa-bookmark"></i> <%= post.created_at %>
</p>
</div>
<div class=" col-xs-2 no-gutter">
<img src="<%= post.author.image %>" class="user-icon" alt="user-image">
</div>
</article>
<% } %>
Please tell me what's wrong with my code .
p/s : the req.params.id is valid and logable.
Default mongo IDs don't increment from 1. They will look like "_id" : ObjectId("5908f94c06515dfa8522459c") in the database. Your problem is your href is navigating by index, not the id itself. You need to change:
<a href="/posts/<%=i%>">
<%= post.title %>
</a>
to:
<a href="/posts/<%=post._id%>">
<%= post.title %>
</a>
this will make your link /posts/5908f94c06515dfa8522459c instead of /posts/1
I'm guessing it's because the id is a string of not 12 bytes (nor 24 hex characters). When the URL comes in to your express web server, it's a string. When express matches a part of it and stores it, there's no rule that :id couldn't be myCoolId, which isn't a number.
So everything in req.params is a string. I would add some checking to make sure it's a number, cast it, and then give it to ObjectId.
EDIT: If you want to work with it as strings, then try some of the following:
const ObjectID = require('mongodb').ObjectID;
// When making a brand new record, just use a new object id.
let record = new ObjectID();
console.log(record);
// When giving the ID to the client as a string, make it a hex string.
let hexString = record.toHexString();
console.log(hexString);
// You can validate that it's a valid object id in your route when they post it back.
let valid = ObjectID.isValid(hexString);
console.log(valid);
// Then you can turn it back into an object id.
let fromHex = ObjectID.createFromHexString(hexString);
console.log(fromHex);

Resources