How to update data in MERN stack - node.js

I am trying to create an Inventory update-route in a MERN stack. My "Add new item" route works perfectly, but the "update route" as refused to update, can someone please tell me what I am doing wrong
//Model
const mongoose= require('mongoose');
const Schema = mongoose.Schema;
//create Schema
const ItemSchema = new Schema({
name : String,
description : String,
price : Number,
quantity : Number,
supplier : String,
taxable : Boolean,
});
module.exports=Inventory=mongoose.model('item',ItemSchema,'inventory');
Routes.js
router.post('/update', (req, res) => {
// inserting a new inventory
var _id = req.body._id;
var inventory = {
name:req.body.name,
description:req.body.description,
price:req.body.price,
quantity:req.body.quantity,
supplier:req.body.supplier,
taxable:req.body.taxable,
};
Inventory.findByIdAndUpdate(_id, { $set: inventory }, { new: true }, function (err, inventory) {
if (err) {
res.status(500);
res.send(err);
} else {
res.status(200);
res.send();
}
});
});
UpdateForm.js
class InventoryUpdateForm extends Component {
constructor(props){
super(props);
this.state = {
_id: this.props.match.params._id,
name: "",
description: "",
price: "",
quantity: "",
supplier: "",
taxable: "",
loading: true,
date: moment(new Date()).format("YYYY-MM-DD"),
};
//some code, basically binding change function with "this"
.........................
//Firstly, I get the entire data for the particular id here
componentWillMount(){
axios.get("/api/inventory/"+this.state._id)
.then(
(res) => {
var newState = {
name: res.data.name,
description: res.data.department,
price: res.data.price,
quantity:res.data.quantity,
supplier:res.data.supplier,
taxable:res.data.taxable,
};
this.setState( newState );
this.setState( { loading: false } );
},
(err) => {
alert('An error occured! Try refreshing the page.', err);
}
);
}
Here i handle the change event cases
handleDatePickerChange(date){
this.setState({ date: moment(date).format("YYYY-MM-DD") });
}
handleNameChange(event){
this.setState({ name: event.target.value });
}
handleDescriptionChange(event){
this.setState({ description: event.target.value });
}
handlePriceChange(event){
this.setState({ price: event.target.value });
handleQuantityChange(event){
this.setState({ quantity: event.target.value });
}
handleSupplierChange(event){
this.setState({ supplier: event.target.value });
}
handleTaxableChange(event){
this.setState({ taxable: event.target.value });
}
And i finally submit
submitForm(){
const { _id, name, description, price, quantity,supplier,taxable} = this.state;
var inventory = {
_id, name, description, price, quantity,supplier,taxable
};
axios.post('/update', inventory)
.then(
(res) => {
alert('Updated successfully!');
},
(err) => {
alert('An error occurred! Try submitting the form again.', err);
}
);
}
The data is retrieved, rendered and I actually update, but when I try to save it I get my error message
back
An error occurred! Try submitting the form again
How do I resolve this?

In axios to catch errors, we add a catch block.
Your submitForm must be like this, can you try and comment what happens?
submitForm() {
const { _id, name, description, price, quantity,supplier,taxable} = this.state;
var inventory = {
_id, name, description, price, quantity,supplier,taxable
};
axios.post('/update', inventory)
.then( res => {
alert('Updated successfully!');
}
)
.catch(err => {
console.log(err.response);
alert('An error occurred! Try submitting the form again.');
});
}
Also in findByIdAndUpdate, there is no need to use $set, you can simply do like this:
router.post("/update", (req, res) => {
console.log("req.body", req.body);
// inserting a new inventory
var _id = req.body._id;
var inventory = {
name: req.body.name,
description: req.body.description,
price: req.body.price,
quantity: req.body.quantity,
supplier: req.body.supplier,
taxable: req.body.taxable
};
Inventory.findByIdAndUpdate(_id, inventory, { new: true }, function(
err,
inventory
) {
if (err) {
console.log("err", err);
res.status(500).send(err);
} else {
console.log("success");
res.send(inventory);
}
});
});
Also can you set the state like this in constructor to match data types in mongoose schema.
this.state = {
_id: this.props.match.params._id,
name: "",
description: "",
price: 0,
quantity: 0,
supplier: "",
taxable: false,
loading: true,
date: moment(new Date()).format("YYYY-MM-DD"),
};
And lastly lets convert our price and quantity number by adding a plus.
handlePriceChange(event){
this.setState({ price: +event.target.value });
handleQuantityChange(event){
this.setState({ quantity: +event.target.value });
}

An alternative is to use the "PUT" method in express.
router.put('/update', (req, res) => {
//Code to update your data
})

Related

Axios Patch Request showing params as undefined in the backed

I want to update data in the server with a Axios Patch call and there seems to be some error in the code which i cant seem to figure out. Help me out please.
Node express API call in the backend:
router.patch('/up',async (req, res) => {
try{
const id = req.query.userid; // User objectid here.
console.log(req.body)
console.log(req.query.userid)
const result= User.findById(id, (error, foundUser) => {
if (foundUser) {
const { products } = foundUser;
const filteredproducts = products.filter((item) => {
return item._id!= req.body.body._id; //product array object id
});
while (foundUser.products.length > 0) {
foundUser.products.pop();
}
foundUser.products = filteredproducts;
foundUser.products.push({
brandname: req.body.brandname,
productname: req.body.productname,
quantity: req.body.quantity,
price: req.body.price,
description: req.body.description
});
foundUser.save();
}
else
{
console.log('User not found')
}
})
res.status(200).send("update successfull");
}
catch(err){
res.status(403).send('update unsuccessfull')
console.log(err)
}
})
Userschema in db:
const userschema = new mongoose.Schema({
username: {
type: String,
},
email: {
type: String,
required: true
},
place: {
type: String,
required: true
},
password: {
type: String,
required: true
},
products:[
{
brandname: {
type:String,
required:true
},
productname:{
type:String,
required:true
},
quantity:{
type:Number,
required:true
},
price:{
type:Number,
required:true
},
description:{
type:String,
required:true
}
}
]
,
tokens:
[{
token: {
type: String,
required: true
}
}
]
})
const User = mongoose.model('USER', userschema)
Front end API code
const updateproduct = async(req,res) => {
console.warn(values.brandname, values.productname,values.quantity, values.price,
values.description)
console.warn("userlogin is:,",userid) // User object id here.
const _id=id; // Product object id here
await axios.patch(`http://localhost:5000/up`,{
headers: {
'Content-type': 'application/json'
},
data: {brandname,productname,quantity,price,description,_id}, //getting the values of all the fields here. checked by console logging them.
params:{
'userid':userid
}
},
{ withCredentials: true })
.then((res) => {
console.log(res)
navigate('/listproduct')
})
.catch((err) => {
console.log(err)
})
}
Sorry if my code look really bad. I am new to React and node.
All i wanna do is edit the product details of a product by the product objectid and store it in the db.
Any other method other than this is also fine. I am stuck with this problem for more than 2 days coudn't find a solution till now. Any help is much Appreciated.
EDIT:
I have tried to update the code but still the same errors.
backend API
router.patch('/up',async (req, res) => {
try{
const id = req.query.userid;
console.log("user id is",id)
console.log("req.body",req.body.body.brandname)
const result= User.findById(id, (error, foundUser) => {
if (foundUser) {
const { products } = foundUser;
const filteredexpenses = products.filter((item) => {
return item._id!= req.body.body._id;
});
while (foundUser.products.length > 0) {
foundUser.products.pop();
}
foundUser.products = filteredexpenses;
foundUser.products.push({
brandname: req.body.body.brandname,
productname: req.body.body.productname,
quantity: req.body.body.quantity,
price: req.body.body.price,
description: req.body.body.description
});
foundUser.save();
}
else
{
console.log('User not found')
}
})
res.status(200).send("update successfull");
}
catch(err){
res.status(403).send('update unsuccessfull')
console.log(err)
}
})
Front end API
const updateproduct = async(req,res) => {
console.warn(values.brandname, values.productname,values.quantity, values.price, values.description)
console.warn("userlogin is:,",userid)
const _id=id;
await axios.patch(`http://localhost:5000/up`,{
headers: {
'Content-type': 'application/json'
},
body:
{'brandname':brandname,'productname':productname,'quantity':quantity,'price':price,'description':description,'_id':_id},
params:{
'userid':userid
}
},
{ withCredentials: true })
.then((res) => {
console.log(res)
navigate('/listproduct')
})
.catch((err) => {
console.log(err)
})
}
Result on console log is
User id is undefined
req.body adidas //brandname
User not found
Try to change your axios request passing all parameters in the body like this:
await axios
.patch(
`http://localhost:5000/up`,
{ brandname, productname, quantity, price, description, _id, userid },
{
headers: {
'Content-type': 'application/json',
},
},
{ withCredentials: true }
)
.then((res) => {
console.log(res);
navigate('/listproduct');
})
.catch((err) => {
console.log(err);
});
And handle the end point like this:
router.patch('/up', async (req, res) => {
try {
const id = req.body.userid;
User.findById(id, async (error, foundUser) => {
if (foundUser) {
const { products } = foundUser;
const { brandname, productname, quantity, price, description, _id } =
req.body;
const filteredexpenses = products.filter((item) => {
return item._id != _id;
});
while (foundUser.products.length > 0) {
foundUser.products.pop();
}
foundUser.products = filteredexpenses;
foundUser.products.push({
brandname,
productname,
quantity,
price,
description,
});
await foundUser.save();
res.status(200).send('update successfull');
} else {
console.log('User not found');
res.status(400).send('User not found');
}
});
} catch (err) {
res.status(403).send('update unsuccessfull');
console.log(err);
}
});

How to update all the data that have same field without modify other data in mongoose?

I have this message collection compose of 4 fields _id, conversationId, message, seen. In my message controller every time the user click specific user the backend will send a list of messages that have same conversationId into the frontend(reactJS). In the frontend that list of messages will be modify by changing the value of seen from false to true. Then I'm planning to pass this to the backend. My problem is how can I modify only all the data that have same conversationId without replacing all of the data inside message collection
Controller that will get all the messages that have same conversationID
export const getMessage = async (req, res) => {
try {
const message = await messageModel
.find({
conversationId: req.params.messageId,
})
.populate('senderId');
res.status(200).json(message);
} catch (error) {
res.status(500).json({ msg: error.message });
}
};
Return Value
[
{
_id: '616d76e858abdc3fa4059ee3',
conversationId: '61696e3ed94cd23f8c22f75a',
message: 'Sample One',
seen: false
},
{
_id: '616d779458abdc3fa4059f53',
conversationId: '61696e3ed94cd23f8c22f75a',
message: 'Sample Two',
seen: false
}
]
Frontend function that will change the value of seen
const handleUpdateSeen= (conversation) => {
dispatch(updateTaskSeenById(conversation));
};
Value that will sending to backend and the output that I want to be change on messageCollection
[
{
_id: '616d76e858abdc3fa4059ee3',
conversationId: '61696e3ed94cd23f8c22f75a',
message: 'Sample One',
seen: true
},
{
_id: '616d779458abdc3fa4059f53',
conversationId: '61696e3ed94cd23f8c22f75a',
message: 'Sample Two',
seen: true
}
]
Solution I made
export const updateMessageSeen = async (req, res) => {
try {
var updatedData;
for (let i = 0; i < req.body.length; i++) {
update = {
_id: req.body[i]._id,
conversationId: req.body[i].conversationId,
senderId: req.body[i].senderId._id,
messageText: req.body[i].messageText,
messageMedia: req.body[i].messageMedia,
seen: req.body[i].seen,
createdAt: req.body[i].createdAt,
};
}
await messageModel.updateMany(
{ conversationId: req.params.conversationId },
updatedData
);
} catch (error) {
res.status(500).json({ msg: error.message });
}
};
You may use Model.updateMany to update multiple documents in a collection.
export const seenMessageById = async (req, res) => {
try {
if (Array.isArray(req.body) && req.body.length > 0) {
const idList = req.body.map( message => message._id);
const result = await messageModel.updateMany({ _id: { $in: idList }}, { seen: true });
res.status(200).json({ msg: `Total ${result.nModified} documents updated` });
} else {
res.status(400).json({ msg: 'Atleast 1 message required to update.' });
}
} catch (error) {
res.status(500).json({ msg: error.message });
}
};

How to set TTL for a mongo DB document through a node js route

I have created a delete account route to delete an users information after certain days. I had used SetTimeOut() function to achieve this. But the problem is if in case for some reason the server gets restarted this does not works. So, is there any other method to achieve this.
Thank you.
Below is the code,
router.post("/delete", async (req, res, next) => {
const mailId = req.body.email;
const deletionTime = moment().format("DD-MMM-YYYY, h:mm:ss a");
await Register.findOne({ email: mailId })
.exec()
.then(async (result) => {
if (req.body.password === result.password) {
await Register.updateOne(
{ email: mailId },
{
$set: {
accountDeleted: true,
deletionFeedback: req.body.deletionFeedback,
latitude: req.body.latitude,
longitude: req.body.longitude,
deletionDate: deletionTime,
deletionIP: req.body.deletionIP,
isp: req.body.isp,
location: req.body.location,
},
}
)
.exec()
.then(async (result) => {
setTimeout(async function(){
await Register.updateOne(
{ email: mailId },
{
$set: {
permanentlyDeleted: true,
},
}
)
.exec();
}, 60000);
res.status(200).json({
userDeleted: true,
});
})
.catch((err) => {
console.log(err);
res.status(400).json({
userDeleted: false,
});
});
} else {
res.status(400).json({
result: 0,
message: "Invalid password.",
});
}
})
.catch((err) => {
res.status(400).json({
result: 0,
message: "Invalid Email ID.",
});
});
});
The thing is if I restart the server the function inside setTimeOut() method doesn't work. Is there any alternative for this.

Updating DB Shema in Express JS with Mongoose library

I have created a Mongo DB schema with Mongoose in Express.js and I am building the REST API. However when I try to update existing records the values that I do not update from the schema automatically become null. I understand why this happens just not sure exactly how it should be coded.
This is the route:
router.patch("/:projectId", async (req, res) => {
try {
const updatedProject = await Project.updateOne(
{ _id: req.params.projectId },
{
$set: {
title: req.body.title,
project_alias: req.body.project_alias,
description: req.body.description
}
}
);
res.json(updatedProject);
} catch (err) {
res.json({ message: err });
}
});
also here is the schema:
const ProjectsSchema = mongoose.Schema({
title: {
type: String,
required: true,
unique: true
},
project_alias: {
type: String,
unique: true,
required: true
},
description: String,
allowed_hours: Number,
hours_recorded: {
type: Number,
default: 0
},
date_added: {
type: Date,
default: Date.now
}
});
My problem is that when I want to update just the title:
{
"title" : "Title Updated33"
}
description and alias become null. Should I implement a check?
Just use req.body for the update object like this:
router.patch("/:projectId", async (req, res) => {
try {
const updatedProject = await Project.updateOne(
{ _id: req.params.projectId },
req.body
);
res.json(updatedProject);
} catch (err) {
res.json({ message: err });
}
});
Or even better, create a helper function like this so that we can exclude the fields in the body that doesn't exist in the model:
const filterObj = (obj, ...allowedFields) => {
const newObj = {};
Object.keys(obj).forEach(el => {
if (allowedFields.includes(el)) newObj[el] = obj[el];
});
return newObj;
};
router.patch("/:projectId", async (req, res) => {
const filteredBody = filterObj(
req.body,
"title",
"project_alias",
"description",
"allowed_hours",
"hours_recorded"
);
try {
const updatedProject = await Project.updateOne(
{ _id: req.params.projectId },
filteredBody
);
res.json(updatedProject);
} catch (err) {
res.json({ message: err });
}
});

Storing all items from Graph API at once

I have my reportSchema.js which is where my schema is defined. I am storing the JSON I get back from the Microsoft Graph API into a variable called result. I want to store each value in the result array into mongodb. I am able to access individual items from the array like this
receivedDateTime: result.value[0].receivedDateTime,
sentDateTime: result.value[1].sentDateTime
But I want to be able to store everything at once. How can I go about doing this? I will post the code down below.
reportSchema
var mongoose = require('mongoose')
var sera = mongoose.Schema({
isRead: Boolean,
subject: String,
from: String,
receivedDateTime: Date,
sentDateTime: Date
});
module.exports = mongoose.model("SERA", sera)
sample of result array
value: [{
'#odata.etag': 'W/"CQAAAA=="',
id: 'AAMkADg4MTBkNmRiLTAwNzQtNDE1Ny1hNjlkLWVjNzE5N2M1MGEwMgBGAAAAAAA9yT6uaq2hTrV0L6GqHQ_CBwALVVFnK27cQ4tC6FzqOc3cAAAAAAEMAAALVVFnK27cQ4tC6FzqOc3cAANuNGz-AAA=',
receivedDateTime: '2019-03-09T03:45:45Z',
sentDateTime: '2019-03-09T03:45:44Z',
subject: 'Re: hw3',
isRead: true,
from: {
emailAddress: {
name: 'Example',
address: 'example.yahoo.com'
}
}
}]
how I am saving the report
SERA.insertMany(result.value, function (error, success) {
if (error) {
console.log("There has been an error inserting")
} else {
console.log("The API data has been stored")
}
})
// save stores into database
SERA.save().then(result => {
console.log(result)
}).catch(function (error) {
console.log("The error is " + error)
});
res.status(201).json({
message: "Handling post request to /api/report",
createdReport: report
});
You can use insertMany() it accepts array of values you want to save.
var mongoose = require('mongoose')
var sera = mongoose.Schema({
isRead: Boolean,
subject: String,
from: {
emailAddress: {
name: String,
address: String
}
},
receivedDateTime: Date,
sentDateTime: Date
});
const Sera = mongoose.model("SERA", sera)
const values = [{
id: 'AAMkADg4MTBkNmRiLTAwNzQtNDE1Ny1hNjlkLWVjNzE5N2M1MGEwMgBGAAAAAAA9yT6uaq2hTrV0L6GqHQ_CBwALVVFnK27cQ4tC6FzqOc3cAAAAAAEMAAALVVFnK27cQ4tC6FzqOc3cAANuNGz-AAA=',
receivedDateTime: '2019-03-09T03:45:45Z',
sentDateTime: '2019-03-09T03:45:44Z',
subject: 'Re: hw3',
isRead: true,
from: {
emailAddress: {
name: 'Example',
address: 'example.yahoo.com'
}
}
}]
Sera.insertMany(values, (error, docs) => {
if(error) {
console.log(error);
} else {
console.log(docs);
}
});
// alternative
// Sera.insertMany(values).then(docs => {
// console.log(docs)
// })
// .catch(error => {
// console.log(error)
// })
https://mongoosejs.com/docs/api.html#model_Model.insertMany

Resources