Business logic works but Mongoose save doesn't - node.js

Hi I'm trying to save data from my shopping cart app to MongoDB database. In my cart controller folder, there are getAllProducts, addOneProduct, removeOneProduct and updateOneProducts methods. All of them run perfectly fine except for updateOneProducts.
The console.log shows:
GET all product { id: [1,2,4], qty: [1,1,1] }
UPDATE one product { id: [1,2,4], qty: [1,1,2] }
which indicate that the business logic works. However, the document is not updated on mLab.
User model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userSchema = new Schema({
username: String,
userID: String,
picture: String,
products: {
id: [Number],
qty: [Number],
}
});
const Users = mongoose.model('User', userSchema);
module.exports = Users;
updateOneProduct
const extractProduct = (user) => {
const product = {};
product.id = user.products.id;
product.qty = user.products.qty;
return product;
}
// if user is logged in n changes the qty of a product, update the qty in database
const updateOneProduct = (req, res) => {
// if (!req.user) return res.status(401).json({ error: 'Unauthorized' });
const userId = req.user._id;
const event = req.body.event;
const productId = req.body.id;
return Users.findById(userId)
.then(user => {
const qty = user.products.qty;
const index = user.products.id.indexOf(productId);
if (index === -1) {
throw new Error(`Product doesn't exist!`);
}
const regex = /^[0-9\b]+$/;
if (event === 'plus') {
qty[index] += 1;
} else if (event === 'minus') {
qty[index] -= 1;
} else if (regex.test(event) && event !== '0') {
qty[index] = Number(event);
}
if (qty[index] === 0) {
user.products.id.splice(index, 1);
qty.splice(index, 1);
}
return user.save();
})
.then(user => {
const product = extractProduct(user);
console.log('UPDATE one product', product);
return res.status(200).json(product);
})
.catch(error => res.status(400).json({ error }));
}

So I basically cloned user.products.qty array with const qty = [...user.products.qty], do operations on it and replace user.products.qty with it using user.products.qty = qty. Lastly, I save it with return user.save().
For some reason, I can't mutate subdocument project and save it. I have to replace the whole subdocument user.products then save for it to work. I think it might also have something to do with this being a PUT request.
// if user is logged in n changes the qty of a product, update the qty in database
const updateOneProduct = (req, res) => {
// if (!req.user) return res.status(401).json({ error: 'Unauthorized' });
const userId = req.user._id;
const event = req.body.event;
const productId = req.body.id;
return Users.findById(userId)
.then(user => {
const qty = [...user.products.qty];
const index = user.products.id.indexOf(productId);
if (index === -1) {
throw new Error(`Product doesn't exist!`);
}
const regex = /^[0-9\b]+$/;
if (event === 'plus') {
qty[index] += 1;
} else if (event === 'minus') {
qty[index] -= 1;
} else if (regex.test(event) && event !== '0') {
qty[index] = Number(event);
}
if (qty[index] === 0) {
user.products.id.splice(index, 1);
qty.splice(index, 1);
}
user.products.qty = qty;
return user.save();
})
.then(user => {
console.log('UPDATE - After save promise', user.products);
return res.status(200).json(user.products);
})
.catch(error => res.status(400).json({ error }));
}

Related

How to create blockUserTime correctly?

I have security.controller, security.service and VerificationEntity.
So, in security.controller I have checkVerificationCode method in which I am trying to block the user if he has exceeded the allowed number of inputs of the wrong code and create the timestamp of the last failed attempt, and then in security.service I'm saving this blockedTime into the blockedTime column in VerificationEntity.
Problem is, when I'm trying to check code again during this block time, blockedTime is updating again. How can I prevent it and make blockedTime static, in order to further compare it with the current timestamp.
security.controller:
public checkVerificationCode = async (req: Request, res: Response) => {
try {
const { mobilePhone, verificationCode, id } = req.body;
const dataToCheck = await this.securityService.checkCode(mobilePhone);
if (verificationCode !== dataToCheck.verificationCode || id !== dataToCheck.id) {
const newTries = dataToCheck.tries + 1;
const triesLeft = +process.env.MAX_CODE_TRIES - +newTries;
if (triesLeft <= 0) {
const blockedTime = await this.securityService.updateBlockTime(mobilePhone, id);
if (timeDiffInMinutes(blockedTime) <= +process.env.USER_BLOCK_EXPIRATION) {
return res.status(StatusCodes.BAD_REQUEST).json({ blockSeconds: `You still blocked` });
}
return res
.status(StatusCodes.BAD_REQUEST)
.json({ blockSeconds: `You was blocked, you can try again after 10 minutes.` });
}
return res.status(StatusCodes.BAD_REQUEST).json({ msg: 'Verification code is invalid' });
}
if (timeDiffInMinutes(dataToCheck.updatedAt) >= +process.env.CODE_EXPIRATION_TIME) {
return res.status(StatusCodes.BAD_REQUEST).json({ msg: 'Verification code expired!' });
}
await this.securityService.resetTries(mobilePhone, id);
return res.status(StatusCodes.OK).json({ msg: 'Success!' });
} catch (error) {
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ msg: error.message });
}
};
security.service:
public async updateBlockTime(mobilePhone: string, id: string) {
const { blockedTime } = await getRepository(VerificationEntity).findOne({ mobilePhone: mobilePhone as string, id });
const timestamp = Date.now();
const blockedTimestamp = new Date(timestamp);
await getRepository(VerificationEntity)
.createQueryBuilder()
.update(VerificationEntity)
.set({ blockedTime: blockedTimestamp })
.where({ mobilePhone: mobilePhone as string, id: id as string })
.execute();
return blockedTime;
}

Express return next() not ending the request

Whenever I send a request, I reach the .then() block and after executing the check(it gets confirmed), the route returns the error as expected. However, the function keeps going and adds the createdAppointment to the database. I've made tried returning just next(), using next(error) only but it keeps giving the same results - it always inserts into the database. Of course, I have the error middleware at the end.
async (err, client) => {
if (err) {
res.status(500).send("Failed Connection!");
return;
}
const forename = req.body.professional.split(" ")[0];
const surname = req.body.professional.split(" ")[1];
const professional = await client
.db("FYP")
.collection("Users")
.findOne({ forename: forename }, { surname: surname });
if (!professional) {
const error = new Error("Professional doesn't match with any in the database")
error.code = 422
return next(error)
}
if(professional.type != "Therapist") {
const error = new Error("The chosen user is not a therapist.")
error.code = 422
return next(error)
}
const user = await client
.db("FYP")
.collection("Users")
.findOne({ _id: res.locals.uid });
const clientUserName = user.forename + " " + user.surname;
const professionalUserName = professional.forename + " " + professional.surname
await client
.db("FYP")
.collection("AppointmentsTherapists")
.find({ client: clientUserName}, { complete: false})
.toArray()
.then(async data => {
if(data) {
console.log(data.length)
for(let i=0; i<data.length; i++) {
console.log(dateInPast(data[i].startTime))
if(dateInPast(data[i].startTime) == false) {
console.log(data[i]._id)
const error = new Error("You already have a booked appointment with a therapist. Please attend the current appointment before booking another.")
error.status = 422
return next(error)
}
}
}
})
if (professionalUserName == clientUserName || user.type == "Therapist" || user.type == "Rehabilitator") {
const error = new Error("A professional cannot book an appointment for themselves.")
error.code = 422
return next(error)
}
const appointment = {
client: clientUserName,
professional: req.body.professional,
information: req.body.information,
startTime: req.body.startTime,
endTime: req.body.endTime,
status: "Pending",
complete: false,
date: new Date()
};
const createdAppointment = await client
.db("FYP")
.collection("AppointmentsTherapists")
.insertOne({ ...appointment });
res.status(200).send(createdAppointment);
return next();
}
);
});
app.use((error, req, res, next) => {
res.status(error.status || 500);
res.json({
message: error.message
})
})
Use async / await or .then() but not both...
let data = await client
.db("FYP")
.collection("AppointmentsTherapists")
.find({ client: clientUserName}, { complete: false})
.toArray()
if(data) {
console.log(data.length)
for(let i=0; i<data.length; i++) {
console.log(dateInPast(data[i].startTime))
if(dateInPast(data[i].startTime) == false) {
console.log(data[i]._id)
const error = new Error("You already have a booked appointment with a therapist. Please attend the current appointment before booking another.")
error.status = 422
return next(error)
}
}
}

Can't save Data in Json Format in Mongodb

In this application, I am saving semester_id, course_id and Subject in Mongodb. All I need is to save the Subject in Json format. I want to save semester_id , course_id and save Subject in Json(not in array) with same ids - For semeter and course. I am saving subject in array and I am new to Angular. Can anyone help me out. Thanks in advance.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var SubjectSchema = new Schema({
semesterId:{type: String,ref:'semesterNew'},
courseId :{type: String,ref:'CollegeCourse'},
subject:{
subject :{ type:String}
},
createdOn : {type:Date,default:Date.now},
updatedOn : {type:Date,default:Date.now},
});
mongoose.model('Subject',SubjectSchema);
router.post('/addSubject',function(req,res){
var subjects = JSON.stringify(req.body.subject);
var subjectData = new subjectModel({
semesterId:req.body.semesterId,
courseId: req.body.courseId,
subject: subjects,
});
subjectData.save(function (err, result) {
if (err) {
console.error(err);
return res.status(400).json({
message: 'Bad Request'
});
} else {
res.json({
status: 200,
data: result
})
console.log('Check',result);
}
});
});
addSubject(item){
return this.api.post(`${this.apiController}/addSubject`,item);
}
saveSubject() {
const config = {
position: NbGlobalPhysicalPosition.BOTTOM_RIGHT
};
const formData = new FormData();
this.subjectMasterForm.controls.semesterCtrl.markAsDirty();
this.subjectMasterForm.controls.collegeCourseCtrl.markAsDirty();
// this.subjectMasterForm.controls.image.markAsDirty();
var all_subject_array = [];
if (this.subjectMasterForm.valid && this.subjectMasterForm.value.subjects.length > 0) {
if (this.semesterSubjectId == '' || this.semesterSubjectId == null || this.semesterSubjectId == 'undefined' || this.semesterSubjectId== undefined) {
var subjects_values = this.subjectMasterForm.value.subjects
var subjects_length = this.subjectMasterForm.value.subjects.length;
subjects_values.forEach(function (element) {
all_subject_array.push(element.name);
console.log('Check2',element.name);
});
this.overview_data = {
courseId: this.courseId,
semesterId:this.semesterId,
subject: all_subject_array,
semesterSubjectId: this.semesterSubjectId,
}
this.collegeTemplateApi.addSubject(this.overview_data).subscribe(data => {
if (data['status'] == 200) {
this.toasterService.show("Subject successfully Added!!!..", `Success`, config);
} else {
this.toasterService.show("Subject Already exists in our Database!!!...", `Success`, config)
}
});
} else {
if(this.courseId!=undefined && this.semesterId!=undefined){
if (this.subjectMasterForm.value.subjects.length > 0) {
var subjects_values = this.subjectMasterForm.value.subjects
var subjects_length = this.subjectMasterForm.value.subjects.length;
subjects_values.forEach(function (element) {
all_subject_array.push(element.name);
});
this.overview_data = {
courseId: this.courseId,
semesterId:this.semesterId,
subject: all_subject_array,
semesterSubjectId: this.semesterSubjectId
}
}
this.collegeTemplateApi.updateSubject(this.overview_data).subscribe(data => {
if (data['status'] == 200) {
this.toasterService.show("Subject successfully Updated!!!..", `Success`, config);
} else {
this.toasterService.show(data['message'], `Success`, config)
}
});
}
}
} else if (this.subjectMasterForm.value.subjects.length == 0) {
this.subjecterror = true;
}
setTimeout(() => this.ngOnInit(), 3000);
}
In your first code segment, the Subject model is not assigned to a variable.
mongoose.model('Subject',SubjectSchema);
Yet later in your code you declare a new instance of subjectModel.
Try assigning the model to this name.
var subjectModel = mongoose.model('Subject', SubjectSchema);

Code executes before i get the response from the database

I am new to Express and writing the code to get the list from my database. I'm trying to update the quantity of the items in my list. Now there can be multiple items and quantity for those items needs to be updated accordingly. The problem I am facing is when I try to get the list and update item accordingly, before my for loop executes to update the item it doesn't update the item's quantity in the database and saves the order. What am I doing wrong?
I have used async functions, promises and flags to update the items quantity in the database but none helps.
This is my code for to get and update the item's quantity
const Express = require("express");
const app = Express.Router();
const Menu = require("../../models/Menu");
const Order = require("../../models/order");
const User = require("../../models/user");
app.post(
"/create",
async function(req, res) {
var myorder = {};
var orderList = [];
var ordDetail = [];
var UpdateMenus = [];
orderList = JSON.parse(JSON.stringify(req.body["OD"]));
if(orderList.length>0){
const user = await User.findOne({ _id: req.user.id })
.then(user => {
if (!user) {
return res.status(400).json({ error: "User Not Found" });
}
})
.then(() => {
var order = Order({
user: req.user.id
});
myorder = order;
(async function loop() {
for (i = 0; i < orderList.length; i++) {
const ordt = new Object({
menu: orderList[i]["menuId"],
order: myorder.id,
prize: orderList[i]["prize"],
quantity: orderList[i]["quantity"]
});
await Menu.findOne({ _id: orderList[i]["menuId"] })
.exec()
.then(menu => {
if (menu) {
if (menu.quantity >= ordt.quantity) {
menu.quantity = menu.quantity - ordt.quantity;
const editmenu = menu;
(async function updateTheMenu() {
await Menu.findOneAndUpdate(
{ _id: menu.id },
{ $set: editmenu },
{
new: true,
useFindAndModify: false
}
).then(updateMenu => {
console.log(updateMenu);
ordDetail.push(ordt);
});
})();
} else {
return res.status(400).json({
error:
menu.MenuText +
"" +
ordt.quantity +
" Qunatity Is Not Available"
});
}
}
});
}
})();
}).then(()=>{
order
.save()
.then(order => {
if (!order) {
return res.json({ error: "Order is not saved" });
}
res.status(200).json(order);
})
.catch(error => {
return res
.status(400)
.json({ error: "Fields are Not Correct" });
});
});
}
}
);
There are few things wrong with your code:
If you use await then you don't need to use then. You can just assign to a variable. Example:
const menu = await Menu.findOne({ _id: orderList[i]["menuId"] })
You don't need to wrap your loop and every await call in async functions. They are already in an async function.
You can write your response handler like this:
app.post('/create', async function(req, res) {
var myorder = {};
var orderList = [];
var ordDetail = [];
var UpdateMenus = [];
orderList = JSON.parse(JSON.stringify(req.body['OD']));
if (orderList.length > 0) {
const user = await User.findOne({ _id: req.user.id });
if (!user) {
return res.status(400).json({ error: 'User Not Found' });
}
var order = Order({
user: req.user.id
});
myorder = order;
for (i = 0; i < orderList.length; i++) {
const ordt = new Object({
menu: orderList[i]['menuId'],
order: myorder.id,
prize: orderList[i]['prize'],
quantity: orderList[i]['quantity']
});
const menu = await Menu.findOne({ _id: orderList[i]['menuId'] });
if (menu) {
if (menu.quantity >= ordt.quantity) {
menu.quantity = menu.quantity - ordt.quantity;
const editmenu = menu;
const updateMenu = await Menu.findOneAndUpdate(
{ _id: menu.id },
{ $set: editmenu },
{
new: true,
useFindAndModify: false
}
);
console.log(updateMenu);
ordDetail.push(ordt);
} else {
return res
.status(400)
.json({
error:
menu.MenuText +
'' +
ordt.quantity +
' Qunatity Is Not Available'
});
}
}
}
try {
const savedOrder = await order.save();
if (!savedOrder) {
return res.json({ error: 'Order is not saved' });
}
res.status(200).json(savedOrder);
} catch (error) {
return res.status(400).json({ error: 'Fields are Not Correct' });
}
}
});

How to Loop Data and Validate in Mongodb

I have a dynamic input field where user can add multiple category at once. Data sent at backend is like
['ELECTRONIC','TOYS','GAMES']
Now I want to check for each element of the array ,if they are already present on mongodb . If its present i want to store it in errors object as
errors={ 0: 'Duplicate Data found'}
I am attaching my code for validation which is not working please help . .
const Category = require('../../models/Category');
const fieldCheck = (req, res, next) => {
const data = req.body;
const errors = [];
for( i = 0; i < data.length ; i++){
Category.findOne({ category_name : data[i]})
.then(user => {
if(user){
// # If a reqistered User ID is found ,then move ahead
errors[i] = 'Duplicate Entry Found';
errors.push(errors[i]);
}
}).catch(err =>{
return res.json(err);
}
)
}
console.log(errors);
};
module.exports = fieldCheck;
My Category Schema is ....
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const categorySchema = new Schema ({
category_name:{
type:String,
unique:true,
isRequired:true,
},
date:{
type:Date,
default:Date.now()
}
});
module.exports = mongoose.model('Category',categorySchema);
You are trying to call an asynchronous method (findOne) inside a synchronous loop (for). As you experience, this is like oil and water.
An easy fix is to make your method asynchronous and use the await keyword, example:
const fieldCheck = async (req, res, next) => {
const data = req.body;
const errors = [];
try {
for( i = 0; i < data.length ; i++) {
let user = await Category.findOne({ category_name : data[i]});
if (user) {
// # If a reqistered User ID is found ,then move ahead
errors[i] = 'Duplicate Entry Found';
errors.push(errors[i]);
}
}
// I assume you wanted to respond to res.json here?
console.log(errors);
} catch (err) {
return res.json(err);
}
};
module.exports = fieldCheck;

Resources