Req.body returns undefined : ExpressJs, NodeJs - node.js

Please help me I'm having this error for 5 days.
I'm trying to delete data inside of my array on MongoDB
but my req.body returns undefined even though I have my body-parser. I'm using axios.patch for request.
It works well in my postman but once I sent data that's where the problem occurs.
Here's my axios api call.
export const deleteTask = (id,post) => api.patch(`/main/${id}`, post);
Here's my schema.
const todoSchema = mongoose.Schema({
username: {
type: String,
},
password: {
type: String,
},
task: [String],
time: {
type: Date,
default: Date.now,
}
});
const TodoModels = mongoose.model('TodoModels', todoSchema);
here's my query.
export const deleteTask = async (req,res) => {
const { id } = req.params;
console.log(req.body);
if(!mongoose.Types.ObjectId.isValid(id))
return res.status(404).json(`Invalid ID`);
await TodoModels.findByIdAndUpdate(id,{$pull:{ task: req.body.task }},{
new: true });
}
My req.body has no task and I don't know why. Once I send data it returns undefined but the ID from req.params is not undefined.
Also once I sent the data from client to backend/server req.body returns this { data: '' } the data I sent became the element. I believe it was supposed to be { task: 'data' }

If your deleting a record then why are you using findByIdAndUpdate ; it should be findByIdAndDelete. I have put a sample code you to refer. There are 2ways you can delete a record. You can try them out and see.
Way 1:
router.delete('/:id', [auth, admin, validateObjectId], async(req, res) => {
//check for existing genre
const movieGenre = await Genre.findByIdAndDelete(req.params.id);
if (!movieGenre) {
return res.status(404).send('No such movie genre found with given id.');
}
res.send(movieGenre);
})
Way 2:
router.delete('/:id', [auth, admin, validateObjectId], async(req, res) => {
//second way to delete
let movieGenre = await Genre.findById(req.params.id);
if (!movieGenre) {
return res.status(404).send('No such movie genre found with given id.');
}
await movieGenre.deleteOne();
const index = genres.indexOf(movieGenre);
genres.splice(index, 1);
res.send(movieGenre);
})
Hope the answer helps you in any way.

Related

Mongoose document _id is null, so when I try to save I get MongooseError: document must have and id before saving

I'm making a discord bot to scrape prices from Amazon. Im using a mongoDB database to store links users give to the bot to track the price of the item the link leads to.
My issue is when I run my code and use the add command, my console reads...
Starting...
Online! Logged in as Amazon Price Tracker#6927
Connected to Database
null
MongooseError: document must have an _id before saving
at C:\Users\logic\Documents\Disc Bot\node_modules\mongoose\lib\model.js:291:18
at processTicksAndRejections (node:internal/process/task_queues:78:11)
Disconnected from Database
I've read the doc's and my understanding is mongoose generates a unique id automatically. I am aware that you can override this my defining an id in your schema, but I haven't done this so I don't know why console.log(a) prints null, and the .save() errors out.
My add.js file
//add function using mongoose for mongodb
const { SlashCommandBuilder } = require("#discordjs/builders");
const mongoose = require("mongoose");
const { MongoDBurl } = require("../config.json");
const Link = require("../Schemas/Link.js");
module.exports = {
//Build the slash command
data: new SlashCommandBuilder()
.setName("add")
.setDescription("add a url to watch list")
.addStringOption(option =>
option.setName("url")
.setDescription("url to add to watch list")
.setRequired(true),
),
//Function that runs when the command is used
async execute (interaction) {
const URL = interaction.options.getString("url");
const user = interaction.user.username;
await interaction.reply(`On it! Adding ${URL} to your watch list`)
//Connect to the database, throws an error if it can't connect
await mongoose.connect(MongoDBurl)
.then( () => console.log("Connected to Database"))
.catch(err => console.log(err));
//Check if the link is already in the database
var exists = await Link.exists({ link: URL}).exec()
.catch(err => console.log(err))
if (exists) {
console.log("This Document Already Exists")
interaction.editReply(`Oops! That link is already in my database.`)
} else {
//If the link dosen't exist, create a document and save it to the database
var newLink = new Link({ user: user }, { link: URL }, { price: "N/A" })
// Debuging variable
var a = newLink.id;
console.log(a)
await newLink.save()
.then( () => {
console.log("Document Saved")
interaction.editReply(`All done! I have saved ${URL} to your watch list.`)
})
.catch(err => {
console.log(err)
interaction.editReply("Oops! Something went wrong, I wasen't able to save this link.")
})
}
//Close the connection when we finish
await mongoose.connection.close()
.then( () => console.log("Disconnected from Database"))
}
};
My Link.js file
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const LinkSchema = new Schema({
user: {
type: String,
requiered: true
},
link: {
type: String,
requiered: true
},
price: {
type: String,
requiered: true
},
})
module.exports = mongoose.model("Link", LinkSchema);
When creating a new modal, the options must be within the same pair of curly braces, however when updating, its separate since you are changing multiple elements.
That's why the error was occurring. You have already shared a working piece of code so I'm guessing you no longer need one.
So I found my issue. I changed this line
var newLink = new Link({ user: user }, { link: URL }, { price: "N/A" })
To
const newLink = new Link({ user: user, link: URL, price: "N/A" });
I don't know why this fixed it, I don't think its because I changed var -> const, and looking at the documentation I thought the first line was the correct way to do this
The line I originally used from the documentation
Tank.updateOne({ size: 'large' }, { name: 'T-90' }, function(err, res) {
// Updated at most one doc, `res.nModified` contains the number
// of docs that MongoDB updated
});
Is this an error in the documentation? or a possible bug? either way the issue is now resolved.

How to add an object to an array of objects in Nodejs?

I'm creating a backend for my React web application and I'm trying to subscribe a user to a match, this match is an object that have an array called "players" and when I click on the join button the username and profilePicture of the user are being dispatched to my backend. The first user info is sent perfectly but when a second user is subscribed the info of the first one is replaced for the second one.
This is my function that push the data:
const playerJoined = async (req, res) => {
const torneoId = req.params.id;
const uid = req.uid;
const profilePicture = req.profilePicture;
const username = req.username;
console.log(req.params);
try {
const torneo = await Torneo.findById(torneoId);
if (!torneo) {
return res.status(404).json({
ok: false,
msg: "Torneo no existe por ese ID",
});
}
const newPlayer = {
profilePicture: profilePicture,
username: username,
};
const nuevoTorneo = {
...req.body,
players: newPlayer,
};
const torneoActualizado = await Torneo.findByIdAndUpdate(
torneoId,
nuevoTorneo,
{
new: true,
}
);
res.json({
ok: true,
torneo: torneoActualizado,
});
} catch (error) {
console.log(error);
res.status(500).json({
ok: false,
msg: "Hable con el administrador",
});
}
};
My frontend is working well because when I added more users the array of objects shows all the players like this:
players: (2) [{…}, {…}]
But on my mongo DB shows only the last user info added like I mentioned before.
I really appreciate any help.
You seem to be replacing the players property instead of pushing into it.
const nuevoTorneo = {
...req.body,
players: newPlayer,
};
When you grab the torneo by id, you should have access to that players property already, so spread that array into your nuevoTorneo as well:
const nuevoTorneo = {
...req.body,
players: [...torneo.players, newPlayer],
};
It is because you always put your newPlayer into the "player" field of your nuevoTorneo and updated the same document. I assume you are using mongoose, You probably should just modify the "torneo" after your query and do something like this:
const torneo = await Torneo.findById(torneoId);
const newPlayer = {
profilePicture: profilePicture,
username: username,
};
torneo.nuevoTorneo.players.push(newPlayer);
await torneo.save();
Or to simply modify your code as:
const nuevoTorneo = {
...req.body,
players: [...torneo.nuevoTorneo.players,newPlayer],
};
I recommend the first method, let me know if you have any questions.

How do I grab information from my mongodb?

I have a schema that's been defined as:
const postSchema = new mongoose.Schema({
url: String,
description: String,
created_date: Date
});
Post = mongoose.model('Post', postSchema)
}
and I have a router that posts and saves it to the database.
router.post('/posts', async function (req, res, next) {
try {
const newPost = new Post({
url: req.body.url,
description: req.body.description,
current_time: req.body.created_date
});
await newPost.save();
res.json('status: success!')
console.log(Post)
console.log(newPost)
} catch (error) {
res.json("status: error! " + error + "could not connect to the database");
}
})
I can see the data in my mongdb and it populates when I enter new data through inputs.
With the code below, the id, url, and description print out when I console log the Post.find();
router.get('/posts', async function (req, res, next) {
let allPosts = await Post.find();
console.log(allPosts)
My question is this, how do I get just the url data out of this? I've tried using:
Post.url
req.query.paramNames
I'm looking through Mongodb documentation but I'm missing something.
Post.find({},{url:1,description:1})
You are doing it wrong. The second parameter should help in selecting the fields you need to find.
This will return an Array. If you are looking for specific document you need to change it to findOne and add the search field on first parameter.

Update record based on username given in Request body

I need to update value in Group db Group_name to the value send in Json payload.
Db schema
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
username: String,
Group_name: {
type: String,
default: '',
}
});
mongoose.model('User', UserSchema);
And API request
router.put('/join', async(req, res) => {
try {
const data = await User.updateOne(req.params.username, {
Group_name: req.body.Group_name
});
console.log(data)
res.send({ msg: "Group Updated!!!" })
} catch (err) {
console.error(err.message);
res.sendStatus(400).send('Server Error');
}
});
currently its updating only first record which is incorrect , my requirement is to check for all records based on username given and according to username given in request parameters ,i will update value of Group_name to the value sent in request body.
can anyone help me ?
Modify query condition.
const data = await User.updateOne(
{ username: req.params.username },
{ $set: { Group_name: req.body.Group_name } }
);
First of all, understand the difference between req.body & req.params
req.body means hidden parameters sent in request body like in post or put requests.
req.params means defined paramters in URL. For this, you must have it defined in your route like below
router.put('/join/:username', async (req, res) => {
// ^^^^^^^^ here it is defined, now you can access it like
const username = req.params.username;
//or
const {username} = req.params; // destructuring
}
there is one more thing and that is
req.query means undefined paramters attached to URL with ?/&
If you want to give username without pre defining like /join?username=john then use req.query
router.put('/join', async (req, res) => {
const {username} = req.query;
}
Then you should use updateMany() function instead of updateOne()
try {
const {username} = req.params;
const {Group_name} = req.body;
const data = await User.updateMany(
{username}, // find as many users where username matches
{Group_name} // update group name from body
);
console.log(data);
The consoled data would be like { n: 2, nModified: 2, ...} because the update queries don't return updated documents but status of the query. If you want to get updated record set, you have to query again with find().
// after update
const updatedRecord = await User.find({ username });
console.log(updatedRecord);
::POSTMAN::
Postman has two types of parameters
Params
Body
If you add in Params it will be added in URL /join?username=john#email.com&Group_name=GroupB and you have to access it in code with req.query.username or req.query.Group_name
If you add in Body it will be hidden and can be accessed with req.body.Group_name etc
Hope it helps!

I define nested schema , when i fill the inputs it returns nothing and not save in Mongodb

I define nested schema but when I send input data returns nothing,
how can I solve this issue ?
this is my result:
{
"message": "handeling post request to /user-api",
"CreatedUserInfo": {
"_id": "5cbb7fbaad28fe209099a57c"
}
}
this is my code :
const userEduSchema = new mongoose.Schema(
{
eduLevel : String ,
eduField : String,
eduInst :String,
eduCity :String,
eduDate :Date,
proposalTitle :String
}
)
const allEduSchema = new mongoose.Schema(
{
bsc: userEduSchema,
master: userEduSchema,
phd: userEduSchema ,
}
)
module.exports = mongoose.model('Users', allEduSchema )
and it is my user.js for save inpute data in MongoDB I don't know this is true or not:
const userModels = require('../../models/userModels')
router.post('/', (req , res, next) => {
const user = new userModels({
_id : new mongoose.Types.ObjectId,
eduLevel :req.body.eduLevel,
eduField :req.body.eduField,
eduInst :req.body.eduInst,
eduCity :req.body.eduCity,
eduDate :req.body.eduDates,
proposalTitle :req.body.proposalTitle,
})
user.save().then(result =>{
console.log(result)
}).catch (err => {
console.log(err)
})
res.status(201).json ({
message:'handeling post request to /user-api',
CreatedUserInfo : user
})
})```
The problem was in defining the way of get the inputs,I must define the nested object and inside of that put the request bodies as well as I define the nested schema.
bsc:{
bscEduLevel :req.body.bscEduLevel,
bscEduField :req.body.bscEduField,
bscEduInst :req.body.bscEduInst,
bscEduCity :req.body.bscEduCity,
bscEduDate :req.body.bscEduDate,
bscProposalTitle :req.body.bscProposalTitle
}
Have you defined userSchema? If not, you are trying to export a schema which does not exist. Again, in case you have not defined userSchema and you want to export allEduSchema, replace the last line of your model file with this:
const EduSchema = mongoose.model("EduSchema", allEduSchema);
module.exports = EduSchema;
Before you create a new user ,you need to require your "User" moongose Schema. Just like dimitris tseggenes said.
I use async function and try/catch to handle this problem.Maybe you could....
router.post("/", async (request, response) => {
try {
const user = new Users({new user's data here..... });
const result = await user.save();
response.send(result);
} catch (error) {
response.status(400).send(error);
}
});
try catch could avoid some unexpected error and handle it.

Resources