Mongoose findByIdAndUpdate not working. {new: true} included - javascript

I tried to edit the info and update it, but the mongoose findByIdAndUpdate didn't work. The {new: true} is included, but it still shows the original one. In the database, the info is not updated either. The console shows PUT /blogs/:id 302.
The routes are as follows:
//edit
router.get('/blogs/:id/edit', function (req, res) {
Blog.findById(req.params.id, function (err, blogFound) {
if(err){
console.log(err);
}else{
res.render("edit", {blog: blogFound});
}
});
});
//update
router.put('/blogs/:id', function (req, res) {
Blog.findByIdAndUpdate(req.params.id, req.body.blog, {new: true},function (err, blogUpdated) {
if(err){
console.log(err);
} else{
res.redirect('/blogs/' + req.params.id);
}
});
});
The edit form looks like this:
<form class="ui form" action="/blogs/<%= blog._id %>?_method=PUT" method="POST">
<div class="field">
<label>Title</label>
<input type="text" name="title" value="<%= blog.title %>">
</div>
<div class="field">
<label>Image</label>
<input type="text" name="image" value="<%= blog.image %>">
</div>
<div class="field">
<label>Content</label>
<textarea name="description"><%= blog.description %></textarea>
</div>
<button class="ui primary button" type="submit">Submit</button>
</form>

it seems req.body.blog is undefined.
you have title, image and description in your body not grouped in blog object, so you shall write
const { title, image, description } = req.body;
Blog.findByIdAndUpdate(req.params.id, { title, image, description },
or smth like this

Related

How to create self referencing MongoDB schema and post routes using nodejs?

I am trying to create parent-child like nested system where child has same schema as of parent.Below is my parent schema, here children refers to the parentSchema again,
var mongoose = require("mongoose");
var parentSchema = new mongoose.Schema({
name: String,
children:[
{
ref: this
}
],
});
module.exports = mongoose.model("Parent", parentSchema);
Routes looks like this
app.get("/", function(req, res){
Parent.find({}).populate("children").exec(function(err, allParents){
if(err){
console.log(err);
}else{
res.render("index",{parents: allParents});
}
});
});
app.post("/", function(req,res){
var name = req.body.name;
var desc = req.body.desc;
var newParent = {name: name, description: desc}
Parent.create(newParent, function(err, newlyCreate){
if(err){
console.log(err);
}else{
res.redirect("/");
}
});
});
app.post("/:id", function(req, res){
Parent.findById(req.params.id, function(err, parent){
if(err){
console.log(err);
res.redirect("/");
}else{
parent.children.push(req.body.child);
parent.save();
console.log(parent.children);
res.redirect("/");
}
});
});
The problem is when I send data from form to post route it prints it but after pushing it into parent.children and then printing parent.children is shows null. Where is the problem???
EJS page looks like below:-
<form action="/" method="POST">
<div class="form-group">
<input type="text" name="name" placeholder="Name">
</div>
<div class="form-group">
<input type="text" name="desc" placeholder="Description">
</div>
<div class="form-group">
<button class=btn-primary btn-block">Submit</button>
Go Back
</div>
</form>
<div class="row">
<% parents.forEach(function(module){%>
<ul class="list-group">
<li class="list-group-item" style="margin-bottom: 5%;">
<h2><%= module.name%></h2>
<%= module.description %>
<% console.log(module.children) %>
<%module.children.forEach(function(node){%>
<% console.log(node) %>
<%});%>
<div class="container">
<div class="row">
<div>
<form action="/<%= module._id %>" method="POST">
<div class="form-group">
<input type="text" name="name" placeholder="Name">
</div>
<div class="form-group">
<input type="text" name="desc" placeholder="Description">
</div>
<button>Submit</button>
</form>
</div>
</div>
</div>
</li>
</ul>
</div>
<% }); %>
</div>
Can anyone tell where is the problem in above code or can anyone suggest any other way to make this type of parent-child structure????
It seems that parent.save() is asynchronus. Maybe you can try this instead.
parent.save().then(()=>{
console.log(parent.children);
res.redirect("/");
});
or you can use async-await after putting async before function definition,
await parent.save();
console.log(parent.children);
res.redirect("/");
Please do write in comment if problem still persists.

Why is form body returning null on PUT request?

Why is the form data not being stored in req.body?
EJS/HTML
<form onsubmit="EditJob()" class="editForm">
<div class="form-group-edit">
<label for="position">Position</label>
<input type="position" id="position" name="position" class="form-control" placeholder="Enter Position Title"
/>
</div>
<div class="form-group-edit">
<label for="company">Company</label>
<input type="company" id="company" name="company" class="form-control" placeholder="Enter Company Name"
/>
</div>
<button type="submit" class="edit">
<i class="fas fa-plus"></i>
</button>
</form>
Client JS
const EditJob = () => {
const id = ####;
const url = `http://localhost:5000/dashboard/${id}`;
axios.put(url).then(res => {
console.log(res);
});
};
Server JS
router.put("/:id", (req, res) => {
Job.findByIdAndUpdate(req.params.id, {
position: req.body.position,
company: req.body.company,
status: req.body.status
})
...
...
});
Updated doc in my database results in {position: null, company: null, status: null}..
Make sure you're using body-parser, or set your express middleware like code below:
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
⚠️ When you're using axios.put(), make sure you passing your data in there. You can read the documentation here
An Example: Axios Put
axios.put(endPoint, data, config).then(...).catch(...)
I hope it's can help you.

send multiple form data to express API with multer

I want to send form data including a file to my express API for adding churches in my database and i want to upload church details and an image for this.
this is my HTML form :
<form action="" id="ad-bis">
<div class="form-group">
<label>INTRODU NUMEle BISERICII</label>
<input
type="text"
name="biserica"
id="biserica"
class="form-control"
/>
<span id="error_biserica" class="text-danger"></span>
</div>
<div class="form-group">
<label>INTRODU ORASUL</label>
<input type="text" name="oras" id="oras" class="form-control" />
<span id="error_oras" class="text-danger"></span>
</div>
<div class="form-group">
<label>INTRODU ADRESA</label>
<input type="text" name="adresa" id="adresa" class="form-control" />
<span id="error_adresa" class="text-danger"></span>
</div>
<div class="form-group">
<label>INTRODU NUME PREOT</label>
<input type="text" name="preot" id="preot" class="form-control" />
<span id="error_preot" class="text-danger"></span>
</div>
<div class="form-group">
<label for="poza">ADAUGA POZA</label>
<input type="file" id="poza" />
</div>
<div class="form-group" align="center">
<button type="submit" name="save" id="save" class="btn btn-info">
SALVARE
</button>
</div>
</form>
in my js file i created submit function:
adBis.addEventListener("submit", async e => {
e.preventDefault();
const data = new FormData();
data.append(
"data",
JSON.stringify({
nume: document.querySelector("#biserica").value,
oras: document.querySelector("#oras").value,
adresa: document.querySelector("#adresa").value,
preot: document.querySelector("#preot").value,
uid: localStorage.getItem("uid")
})
);
data.append("poza", _("#poza").files[0]);
console.log(data);
const res = await await fetch("http://localhost:8080/api/site/adaugare", {
method: "POST",
body: data
});
const serverData = await res.json();
console.log(res, serverData);
_(".info").style.display = "none";
if (!serverData.success) {
afisareEroare(data.msg);
}
console.log("ok");
await afisRezultate(localStorage.getItem("uid"));
});
then i created endpoint in express using multer tu upload file:
const multer = require("multer");
const storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, "../images");
},
filename: function(req, file, cb) {
cb(null, file.fieldname + "_" + Date.now() + "_" + file.originalname);
}
});
const upload = multer({
storage: storage
}).array("imgUploader", 3);
outer.post("/adaugare", (req, res) => {
console.log(req.body);
res.json({ msg: "ok" });
/*
*/
});
in my console, req.body is empty how send all data?
I tried with firebase storage but it doesn't work for me.
what I missed?
thanks!
First tip: Since you are using FormData you can pass the form in to get automatically all the values in the form.
Second, here you are awaiting twice:
const res = await await fetch("http://localhost:8080/api/site/adaugare", [...]
Lastly req.body empty is either because of lack of body-parser or, as I see here, you have not added the enctype="multipart/form-data" attribute, without this Multer won't get any data from your form.

Server unable to find view for POSTbut can find it in GET

I have some code that is supposed to validate a user logging into my server, however it doesn't want to post it. My get request has no problem loading the very same "/login" as my post but for some reason it doesn't want to load it during the POST. Sorry if my code is a little inefficient and hard to read, still trying to get the hang of javascript.
app.post("/login", (req, res) => {
req.body.userAgent = req.get('User-Agent');
dataServiceAuth.checkUser(req.body).then((user) => {
req.session.user = {
userName: user.username,
email: user.email,
loginHistory: user.loginHistory
}
res.redirect('/employees');
}).catch((err) => {
res.render("login", {errorMessage: err, userName: req.body.userName});
});
});
and the function in the POST
module.exports.checkUser = function (userData) {
return new Promise(function (resolve, reject) {
User.find({ user: userData.userName }).exec().then((user) => {
if (user == undefined || user.length == 0) {
reject("Unable to find user: " + userData.userName);
}
else if (user[0].password != userData.password) {
reject("Incorrect Password for user: " + userData.userName);
}
else if (user[0].password == userData.password) {
users[0].loginHistory.push({dateTime: (new Date()).toString(), userAgent: userData.userAgent});
user[0].update({userName: userData.userName}, {$set: {loginHistory: user[0].loginHistory}}.exec().then((user) => {
resolve(user[0]);
}).catch((err) => {
reject("There was an error verifying the user: ${err}");
}))
}
}).catch((err) => {
reject("Unable to find user: " + userData.user);
});
});
};
My Tree looks like this
and my Handlebars file looks like this
<!DOCTYPE html>
<html lang="en">
<body>
<div class="container">
<div class="row">
<div class="col-md-12">
<h2>Log In</h2>
<hr />
{{#if errorMessage}}
<div class="alert alertdanger">
<strong>Error:</strong> {{errorMessage}}</div>
{{/if}}
<form method="post" action="/login">
<div class="row">
<div class="col-md-12">
<div class="form-group">
<input class="form-control" id="userName" name="userName" type="text" placeholder="User Name" required value=""
/>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<input class="form-control" id="password" name="password" type="password" placeholder="Password" required />
</div>
</div>
</div>
<input type="submit" class="btn btn-success pull-right" value="Login" />
</form>
</div>
</div>
</div>
</body>
</html>
Express version 4 and above requires extra middle-ware layer to handle POST request. This middle-ware is called as ‘bodyParser’. This used to be internal part of Express framework but here I think you need to install it separately like this npm install --save body-parser
Firstly, You should realize that requesting the same route through GET and POST methods does different things.
When you use the GET method, the reason that it has no problem loading the page is because (from what I assume) you would have specified a specific file (probably this login form) to be rendered when a request is received.
In case of the POST request though, you are carrying out operations on the form data sent with the request, and hence there could be a number of reasons you're facing issues with it. Maybe you haven't configured bodyParser to parse nested objects, as Yaswant's answer stated. Or maybe there's some other issue in your code.
It would be helpful if you could give a little more detail on what error you're facing, and if you could post your complete app.js file.

Delete list items using Node.js Express Mongoose

I am trying to delete elements after retrieving them from the database using mongoose. However i am stuck at a part where i do not know how to 'grab' one particular element in the list and then how to delete it.
In my app, i have a list of users and their age.
Here is my userview.ejs (EDITED after adding frontend.js)
<meta charset="UTF8">
<link href="../public/javascripts/frontend.js">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="/stylesheets/userlist.css">
<link href='//fonts.googleapis.com/css?family=Amatic SC' rel='stylesheet'>
<link href='//fonts.googleapis.com/css?family=NTR' rel='stylesheet'>
<html>
<head>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<title>Userlist</title>
<script src="javascripts/frontend.js"></script>
<script>
</script>
</head>
<div class="container-fluid">
<div class="row">
<h1><strong>FORM</strong></h1>
<hr id="hr2" style="border: 6px solid palevioletred" >
<div id="black">
<form class="form-horizontal" method="post" action="/users">
<fieldset>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Name : </label>
<div class="col-md-4">
<input id="textinput" name="name" placeholder="Enter Username" class="form-control input-md" type="text" value="Name" onfocus="if (this.value=='Name') this.value='';">
</div>
</div>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Age : </label>
<div class="col-md-4">
<input id="textinput" name="age" placeholder="Enter Age" class="form-control input-md" type="number">
</div>
</div>
<!-- Button -->
<!-- Button (Double) -->
<div class="form-group">
<div class="col-md-8">
<button id="singlebutton" name="button1id" class="btn btn-success">Add User</button>
</div>
</div>
<body>
<h1><strong>USERS</strong></h1>
<hr id="hr1" style="border: 6px solid #7ec4ec;" >
<ul id="list" class="triangle">
<% for(var i=0; i<userlist.length; i++) {%>
<li><%= userlist[i].name %> : <%= userlist[i].age %> Delete || Update</li>
<% } %>
</ul>
</body>
</fieldset>
</form>
</div>
</div>
</div>
</html>
EDIT:
This is my frontend.js
var $ = require('jquery');
function delete_element (userId) {
$.post('delete/user/',userId,function(){
alert('Deleting....'); //For now i have just added an alert.
});
}
This is my new users.js
'use strict'
var express = require('express');
var router = express.Router();
var User=require('../models/usermodel.js');
var $= require('jquery');
/* GET users listing. */
router.get('/', function(req, res, next) {
User.find({},function(err,userModel){
res.render('userview',{userlist:userModel});
});
});
router.post('/', function(req, res, next) {
var newUser = new User({
name:req.body.name,
age: req.body.age
});
console.log(newUser);
// save the user
newUser.save(function(err) {
if (err) throw err;
console.log('User created!');
});
});
router.post("delete/user/:id", deleteUser);
function deleteUser(req,res){
User.findById(req.params.id).remove().exec(function(err){
if (!err) {
console.log('Removed Successfully');
}
else {
console.log('Error in removing the entry');
}
});
}
/*
function delete_element(id){
$('#delete').on("click",function(){
$(this).parent().remove();
});
User.remove({_id: req.body.id }, function(err) {
if (!err) {
console.log('Removed Successfully');
}
else {
console.log('Error in removing the entry');
}
});
}
*/
/*router.post('/', function(req, res, next) {
userModel.update( {name: req.params.name}, { $pullAll: {uid: [req.params.deleteUid] } } )
});*/
module.exports = router;
Embed the user's _id in your delete link :
onclick="delete_element('<%= userlist[i]._id %>')"
This will produce :
onclick="delete_element('55510c6cf0e19f6414b30f97')"
and pass the user's _id to your delete function.
Edit
Okay so, apparently, you're trying to call a function defined on the server (Node), directly from your view (HTML).
That's absolutely not how it works :)
onclick="delete_element()" is calling a function locally, in your browser. The console (F12) must yell error : delete_element is undefined.
So the way to go is the following :
1) Create a javascript function (not in Node, in your front-end application) that will call the server.
function delete_element (userId) { // This will be called on click and passed the user's _id
$.post('delete/user/'+userId) // This calls the server. Todo : add a callback, etc.
}
2) Your Node server must have a corresponding route that will receive the call :
router.post("delete/user/:id", deleteUser); // This is reached when the client calls post('delete/user/1a2b3c4d'). The id is read with req.params.id
deleteUser = (req,res) => {
User.findById(req.params.id)
.remove()
.exec( error => { // Reply to the client, otherwise the request will hang and timeout.
if(error) return res.status(500).send(error);
res.status(200).end()
})
}
That's for the first question, please create a new question for the second one.

Categories