Check if variable is empty not working | NodeJS, Express - javascript

I am trying to build a blog API, and right now I have three fields in my schema:
const PostSchema = new Schema({
timestamp: {
type: Date,
default: Date.now
},
title: {
type: String,
required: [true, "Title is required"]
},
content: {
type: String,
required: [true, "Content is required"]
}
})
I also have createPost function, that is supposed to create a post (no shit):
// Create post
const createPost = (req, res, next) => {
const title = req.body.title
const content = req.body.content
console.log('body', req.body) // getting output
if (!title) {
res.status(422).json({ error: "Titel saknas!!!" })
}
if (!content) {
res.status(422).json({ error: "Skriv något för fan!" })
}
const post = new Post({
title,
content
})
post.save((err, post) => {
if (err) {
res.status(500).json({ err })
}
res.status(201).json({ post })
})
}
I have those two if statements to check if the title or the content is empty, but that is not working. I tried to send a POST request with Postman:
But the error says that my title is missing. But I am passing in my title key.
So I wonder why this is not working, it feels like some obvious stuff, but I just can't get this to work.
Thanks for reading.

I don't know Postman too well, but I'm going to guess that setting the body content type to raw uploads the body as text/plain, which means body-parser will not parse it in any way (console.log('body', typeof req.body) will show "body string").
Instead, try setting the content type to application/json (and make sure that your server uses the JSON middleware from body-parser).

Related

unable to push object returned from mongoose query

I am making a social media backend.
I save post added by the used in a Post model and user data in a User model.
GITHUB_REPO_LINK_AT_END
NOTE: UserSchema have a Schema.TypesOf.ObjectId Reference To POST Model. User_Model_&_Post_Model_are_provided_in_the_end
To get all posts of a particular user, I make a GET request to the route "/post" with body:
{ "id" : "6399d54c00308a2fe0bdf9fc"} //sending user id to fetct all the ID of the post from USER model, so i can then query the POST model for the posts
This the function I am getting problem with:
const getPost = async(req, res)=>{
if(req.body.id){
try {
const user = await User.findById(req.body.id).select('-_id post');
//THIS IS THE PART I NEED HELP WITH-------------------------------------------
const posts = await user.post.map(async(postID) => {
const result = await Post.findById(postID).select('-_id title body');
//console.log(result) THIS PRINTS THE CORRECT OBJ FROM DB
return result; //THIS RETURNS AN EMPTY OBJECT HERE
});
//----------------------------------------------------------------------------
res.status(200).json(posts);
} catch (error) {
console.log(error);
res.status(500).json({message: error.message});
}
}
};
when sending a GET request it returns an empty array with empty objects.//PS: no. of empty obj = actual no. of obj in DB
//This is the response
[{},{},{},{},{},{},{},{},{},{},{}]
{
//This is the user object
"_id": "6399d54c00308a2fe0bdf9fc",
"createdAt": "2022-12-14T13:52:40.483Z",
"name": "ShivamUttam",
"username": "Fadedrifleman",
"post": [
"6399d57200308a2fe0bdfa00",
"6399d5c400308a2fe0bdfa06",
"6399d5ca00308a2fe0bdfa0a",
"6399d5d600308a2fe0bdfa0e",
"6399de29e8aa8697299941c5",
"6399dec6e9b79ac66c59cd7a",
"6399df0dbea937f8b3365979",
"6399df31bea937f8b336597d",
"6399df31bea937f8b3365981",
"6399df32bea937f8b3365985",
"6399df33bea937f8b3365989"
],
"__v": 5
}
Model for USER and POST:
User:
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
createdAt: {
type: Date,
default: Date.now()
},
name: {
type: String,
required: [true, 'name must be provided'],
},
username : {
type: String,
required: [true, 'Username must be provided'],
},
post:[{
type: mongoose.Schema.Types.ObjectId,
ref: 'Post',
}],
});
module.exports = mongoose.model('User', userSchema)
Post:
const mongoose = require('mongoose')
const postSchema = new mongoose.Schema({
createdAt: {
type: Date,
default: Date.now()
},
title:{
type: String,
required: [true, "title cannot be empty"],
max: [20, "title cannot exceed 20 character"]
},
body: {
type: String,
max: [145, "body cannot exceed 145 character"],
},
tags:{
type: String,
},
});
module.exports = mongoose.model('Post', postSchema);
https://github.com/Fadedrifleman/socialMediaAppBackend/tree/master
Since you have used async callback function in the map method, a async function always return a promise, whatever the entity is returned by the function is wrapped inside a promise and that promise is returned.
If you want to use map function with async js code, you can try the following
const posts = await Promise.all(user.post.map(async(id)=>{
const result = await Post.findById(postID).select('-_id title body');
return result;
}));
and if you want to straightaway send the posts, you can also use .lean() method on posts, as in
await Post.findById(postID).select('-_id title body').lean()
You had some bugs that probably would interfere, I did a pull request to fix them: https://github.com/Fadedrifleman/socialMediaAppBackend/pull/1
But the main part would be this:
const getPost = async (req, res) => {
try {
if (req.body.id) {
const user = await User.findById(req.body.id);
await user.populate("post");
res.status(200).json(user.post);
return;
}
const posts = await Post.find({ access: 'public' }).select('-access');
res.status(200).json(posts);
} catch (error) {
res.status(500).json({ message: error.message });
}
};

How to count all comments that are in the same individual post?

I'm trying to count the number of comments made in a specific post but I am getting an undefined error...
The post and comments are in the mongodb.
The current Error I get in the console:
{stringValue: '"undefined"', valueType: 'string', kind: 'ObjectId', value: 'undefined', path: 'post', …}
My current code in the server-side:
//Get all amount of comments of the individual post
app.get("/:postId/comments/all", async (req, res) => {
try {
const comments = await Comment.countDocuments({
post: req.params.postId,
});
res.send(comments);
} catch (err) {
res.send({ error: err });
}
});
My current code in the client-side:
//Get comments quantity from the server
const getAllComments = async () => {
const res = await axios.get(`/api/posts/${postId}/comments/all`);
if(res.data.error){
setComments("");
console.log(res.data.error);
} else {
setComments(res.data);
}
};
Comment Schema:
const Comment = new mongoose.Schema({
post: {
type: Schema.Types.ObjectId,
ref: "post",
},
What I've tried:
I've tried looking different examples on how it's done but failed.
I tried using .find(postid).count() and send it to the front-end.
It appears to be that no matter what I do, it returns me undefined.
I've been trying to play around with it but had no luck.
I'd appreciate your support on this problem.
I was trying to use .countDocument() in the wrong route that had no :postId in there.
I added in my post Schema:
commentsCount: {
type: Number,
default: 0,
},
And then when a client submits a comment to a specific post, in server-side I increment the 'commentsCount' by one and then I render it on a specific post when the page loads.

How do I send data to express backend from html frontend without a form?

I am trying to create a small ecommerce website where I need to have a cart page. I need to make it so when a user clicks on Add to cart button, the particular item will get sent to the backend and stored in the cart collection.
What I'm having trouble with is that when I click the add to card button and the function linked to it runs, I get an error stating : SyntaxError: Unexpected token " in JSON at position 0
Here's my function which is supposed to send data to the backend:
let addToCart = async (item) => {
// item is the object I get which contains all the information I need
try {
let product = item._id;
await fetch('http://localhost:5000/cart', {
method: 'post',
body: product,
headers: {
'Content-Type': 'application/json',
},
});
} catch (e) {
console.log({error : e});
}
};
This is my cart model :
const cartSchema = new mongoose.Schema(
{
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'users',
required: true,
},
cartProducts: {
type: Array
},
},
{
versionKey: false,
timestamps: true,
}
);
This is my cart controller POST CRUD
router.post('', authenticate, async (req, res) => {
const user = req.user;
console.log(user);`
try {
const cart = await Cart.findOneAndUpdate(
{ userId: user._id },
{
$push: {
cartProducts: req.body,
},
},
{ new: true, upsert: true }
);
return res.status(200).send(cart);
} catch (err) {
return res.status(400).send({ message: err.message });
}
});
I am able to get user using authenticate middleware.
I can post everything using Postman but I can't figure how to get rid of the Syntax error.
When I console.log typeof item, I get an object. Product's type is string. I have also tried using JSON.stringify but nothing seems to be working. I have also tried using bodyparser middleware.

TypeError: Cannot use 'in' operator to search for 'userId'

So i was implementing a users model in my mvc and then i get a weird error saying
MongoClient constructor.
D:\node\node_modules\mongoose\lib\document.js:2022
if (path in this.$__.selected) {
^
TypeError: Cannot use 'in' operator to search for 'email' in saifkhan501721#gmail.com
at model.isSelected (D:\node\node_modules\←[4mmongoose←[24m\lib\document.js:2022:14)
at D:\node\node_modules\←[4mmongoose←[24m\lib\document.js:2195:14
at Array.filter (<anonymous>)
at _getPathsToValidate (D:\node\node_modules\←[4mmongoose←[24m\lib\document.js:2194:71)
at model.Document.$__validate (D:\node\node_modules\←[4mmongoose←[24m\lib\document.js:2365:23)
at D:\node\node_modules\←[4mkareem←[24m\index.js:369:33
←[90m at processTicksAndRejections (internal/process/task_queues.js:79:11)←[39m
i have no idea as to what is the reason behind the error is, is it a syntax error , logical error connection error or mispelling of a variable,well anyway here's my app.js
mongoose
.connect('mongodb+srv://turd_waffle:SaifKhan#cluster0.lltqs.mongodb.net/shop?retryWrites=true&w=majority')
.then((result) => {
User.findOne().then(user=>{
if(!user){
const user=new User({
name:'Saif',
email:'saifkhan501721#gmail.com',
cart:{
items:[]
}
})
user.save()
}
})//save() saves the documents(mostly used as a reference to generate a sample id in order to start a cluster working)
app.listen(3000)
})
.catch(err => {
console.log(err)
})
here's my user.js model to store users data in mongodb database
const mongoose = require('mongoose')
const Schema = mongoose.Schema;
const userSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
cart: {
items: [{
productId: {
type: Schema.Types.ObjectId,
ref: 'Product',
required: true
},
quantity: {
type: Number,
required: true
}
}]
},
})
userSchema.methods.addToCart = function(product) {
const cartProductIndex = this.cart.items.findIndex(cp => {
return cp.productId.toString() === product._id.toString();
})
let newQuantity = 1;
const updatedCartItems = [...this.cart.items];
if (cartProductIndex >= 0) {
newQuantity = this.cart.items[cartProductIndex].quantity + 1;
updatedCartItems[cartProductIndex].quantity = newQuantity
} else {
updatedCartItems.push({
productId: product._id,
quantity: newQuantity
})
}
const updatedCart = {
items: updatedCartItems
}
this.cart=updatedCart
return this.save()
}
module.exports = mongoose.model('User', userSchema)
can anyone please be kind enough to atleast tell me what the error above is trying to say i used app.use to create a user so i can store his id, email and name
app.use((req, res, next) => {
User.findById('5f788c080ba19e0f8c642202')
.then(user => {
req.user = new User(user.name, user.email, user.cart, user._id);
next();
})
.catch(err => console.log(err));
});
Strange issue. From the code you provided, the issue should not arise.
When I look at the code in mongoose, the only way that this could happen is if you would do something like:
new User("saifkhan501721#gmail.com")
Then this.$__.selected would be a string instead of an object (e.g. {email: "saifkhan501721#gmail.com"}) and path in this.$__.selected would cause your received type error.
Not knowing enough about your app, I would assume that there maybe is a bad User object created somewhere else / cached / or already in database. Maybe it would help to verify this using a clean database?
See the source code for reference. When I take a look at the code it seems like an oversight that it is not checked if this.$__.selected is a string, because in this case it does not fail early (e.g. Object.keys(this.$__.selected) will not cause an error).

Sending empty {} after form "post" with pug in node.js

I'm trying to pass form data from login page to signin page via post using fetch with this pug code:
form(id="form-login")
input(type="text", name="email", value="", placeholder="Tu email")
br
input(type="password", name="password", value="", placeholder="Tu contraseña")
br
input(type="submit" value="Conectar")
script.
const formLogin = document.querySelector('#form-login');
const formData = new FormData(formLogin);
formLogin.addEventListener('submit', function(event) {
console.log('Form Data: ', formData);
event.preventDefault();
fetch('/signin', {
method: 'POST',
body: formData
})
.then(function(res) {
res.json();
})
.then(function(data) {
console.log(data)
localStorage.setItem('token', data.token)
})
});
The problem is an empty req.body reaching to signin.. After trace it gives this console.log
Form Data: FormData {}
and also an undefined req.body.
If I comment this script and just send it through form adding action="/signin" and method="post", it works and the answer is printed, but calling storage.setItem({ token: <token> }) returns an Uncaught (in promise) TypeError: Cannot read property 'token' of undefined
I'm wondering why this script is not sending the data... can't figure out... so any help will be much apreciated.
Signin function:
function signIn (req, res) {
if (!req.body.email) return res.status(200).send({message: 'No recibo el usuario'})
User.findOne({ email: req.body.email }, (err, user) => {
if(err) return res.status(500).send({ message: err })
if(!user) return res.status(404).render('login', { title: 'Intenta loguearte de nuevo' })
user.comparePassword(req.body.password, (error, isMatch) => {
if (error) return res.status(500).send({ message: error })
if (!isMatch) {
return res.redirect('login')
} else {
req.user = user
res.status(200).send({
message: 'Te has logueado correctamente',
token: service.createToken(user)
})
//$window.localStorage.setItem({token: service.createToken(user)}); // NO WORKS
return res.body = service.createToken(user) // TRYING THIS WITHOUT KNOWLEDGE ABOUT WHAT AM I DOING :O
}
})
})
}
Thanks in advance.
****EDIT****
As #MichałSałaciński suggest, commenting first .then res.json().... At least gives a response, but still don't undestand what's hapenning here and in order to learn properly and make things better, also hope someone can explain how to correctly do stuff like this.
Response: body : ReadableStream
locked : false
__proto__ : Object
bodyUsed : false
headers : Headers
__proto__ : Headers
ok : true
redirected : false
status : 200
statusText: "OK"
type : "basic"
So I was having the same issue where the POST request from my pug form was sending back an empty {} as the req.body object. The code was a simple create action using these:
bookController.js
exports.createBookForm = (req,res) => {
res.render("create_book_form", { title: "Add A New Book"})
}
exports.createBook = (req,res) => {
const reqFields = ["title", "author"];
for (let i = 0; i < reqFields.length; i++) {
const field = reqFields[i];
if (!field in req.body) {
const message = `Missing ${field} in the request body`;
console.log(message)
return res.status(400).send(message)
}
}
Book
.create({
title: req.body.title,
author: req.body.author,
summary: req.body.summary
})
.then((book) => {
res.status(201).json(book.serialize())
})
.catch(err => {
console.log(err);
})
}
And the create book form:
block content
h1 Add a Book
h3 Do use real details. Otherwise, what's the point?
form(method="POST" action="/books")
div.form-group
label(for="title") Title:
input#title.form-control(type="text", placeholder="Small Gods" name="title")
label(for="author") Author:
input#author.form-control(type="text", placeholder="Terry Pratchett" name="author")
label(for="summary") Summary:
textarea#summary.form-control(type="text", placeholder="God is turtle, world is flat" name="summary")
div.form-group
button.btn.btn-primary(type="submit" role="submit") Add Book
What finally fixed getting the actual req.body to show up for the POST action was adding (within server.js)
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
Let me know if this works for you. Took me a couple hours to come to this conclusion and I hate seeing questions go unanswered.
You should move "new FormData" inside "send" event listener. Also, there's missing comma after type="submit", but overall, the problem got nothing to do with pug :)
form(id="form-login")
input(type="text", name="email", value="", placeholder="Tu email")
br
input(type="password", name="password", value="", placeholder="Tu contraseña")
br
input(type="submit",value="Conectar")
script.
const formLogin = document.querySelector('#form-login');
formLogin.addEventListener('submit', function(event) {
const formData = new FormData(formLogin);
console.log('Form Data: ', formData);
event.preventDefault();
fetch('/signin', {
method: 'POST',
body: formData
})
.then(function(res) {
res.json();
})
.then(function(data) {
console.log(data)
localStorage.setItem('token', data.token)
})
});

Categories