Code executes before i get the response from the database - node.js

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' });
}
}
});

Related

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)
}
}
}

display questions based on user type MERN

I have two collections from one questions for admin comes and from other questions for user comes.
I am unable to show the questions in React using redux store.
store/action
import { QUESTIONS } from '../../constants/actionTypes';
import * as api from '../../services/api';
import * as paths from '../../constants/apiPaths';
const TOTAL_QUESTIONS = 60;
export const fetcQuestions = (router) => async (dispatch) => {
try {
const user = await api.get(paths.FETCH_USER);
const userType = user.type;
console.log(userType + "userType");
if((userType === "Student") || (userType === "STUDENT"))
{
const {questions, assessment, options} = await api.get(paths.FETCH_QUESTIONS);
console.log(api.get(paths.FETCH_QUESTIONS) + "Question path");
dispatch({ type: QUESTIONS, questions, assessment, options });
if(assessment.responded === TOTAL_QUESTIONS) {
router.push('/advice');
}
}
else
if((userType === "Admin") || (userType === "ADMIN"))
{
console.log(userType + "type of user");
const {questions, assessment, options} = await api.get(paths.FETCH_QUESTIONS);
console.log(api.get(paths.FETCH_QUESTIONS) + "Question path");
dispatch({ type: QUESTIONS, questions, assessment, options });
if(assessment.responded === TOTAL_QUESTIONS) {
console.log("thank you");
}
}
} catch (error) {
console.log(error);
}
};
export const postAssessment = (data, router) => async (dispatch) => {
try {
const {questions, assessment, options} = await api.post(paths.POST_ASSESSMENT, data);
console.log(paths.POST_ASSESSMENT + "assessment");
dispatch({ type: QUESTIONS, questions, assessment, options });
if(assessment.responded === TOTAL_QUESTIONS) {
console.log("Thank you");
}
} catch (error) {
console.log(error);
}
};
please help me looking out whats wrong I am doing here. Thank You.
Reducer:
import * as actionType from '../../constants/actionTypes';
const assessmentReducer = (state = { questions: null, assessment: null, options: null }, action) => {
switch (action.type) {
case actionType.QUESTIONS:
return { ...state, questions: action?.questions, assessment: action?.assessment, options: action?.options, loading: false, errors: null };
default:
return state;
}
};
export default assessmentReducer;
NodeJS controller:
const TOTAL_QUESTIONS = 120;
export const fetchQuestions = async (req, res) => {
try {
const user = await db.findOne('USER', { _id: req.userId});
console.log(user + "user data");
let answerdQuestions = [];
let nextQuestions;
let assessment;
if (user.assessment) {
assessment = await db.findOne('ASSESSMENT', { user: req.userId });
answerdQuestions = assessment.responses.map(response => response.number)
}
nextQuestions = getNextQuestions(answerdQuestions);
if ((user.type === "STUDENT") || (user.type === "student")) {
console.log(user.type + "type");
const questions = await db.find('QUESTIONG', { number: { $in: nextQuestions } });
console.log(questions.number + "quesstudent");
res.status(200).json({ questions, assessment: { id: assessment?._id, responded: answerdQuestions.length }, options: options });
return answerdQuestions;
}
else {
console.log(user.type + "typegh");
const questions = await db.find('QUESTION', {number: { $in: nextQuestions }});
console.log(questions.question + "quesdata");
res.status(200).json({ questions, assessment: { id: assessment?._id, responded: answerdQuestions.length }, options: options });
return answerdQuestions;
}
} catch (err) {
console.log(err)
res.status(500).json({ message: "Something went wrong" });
}
};
export const postResponses = async (req, res) => {
try {
let responses = req.body.responses;
let assessmentId = req.body.id;
responses = responses.map(response => {
return {
score: Number(response.value),
number: response.number,
category: response.category,
question: response._id
}
});
const user = await db.findOne('USER', {_id: req.userId});
console.log( user.type + "typeofuser");
let assessment = await db.findOne('ASSESSMENT', { _id: assessmentId });
if (assessment?.responses.length === TOTAL_QUESTIONS) {
res.status(200).json("completed");
}
if (!assessment) {
//
let response = {
user: req.userId,
responses: responses,
responded: responses.length
}
assessment = await db.create('ASSESSMENT', response);
await db.findOneAndUpdate('USER', { _id: req.userId }, { assessment: assessment._id });
} else {
assessment = await db.findOneAndUpdate('ASSESSMENT', { _id: assessment._id }, { $push: { responses: { $each: responses } } });
}
let answerdQuestions = assessment.responses.map(response => response.number);
const nextQuestions = getNextQuestions(answerdQuestions);
if (answerdQuestions.length === TOTAL_QUESTIONS) {
console.log("You win");
]
}
if((user.type === "STUDENT") || (user.type==="student") ){
console.log("type" + user.type);
const questions = await db.find('QUESTIONG', { number: { $in: nextQuestions } });
res.status(200).json({ questions, assessment: { id: assessment?._id, responded: answerdQuestions.length }, options: options });
} else
{
console.log(user.type + "typeg");
const questions = await db.find('QUESTION', { number: { $in: nextQuestions } });
res.status(200).json({ questions, assessment: { id: assessment?._id, responded: answerdQuestions.length }, options: options });
}
}catch (err) {
console.log(err)
res.status(500).json({ message: "Something went wrong" });
}
};
//export default fetchQuestions;
I have added reducer and NodeJS controller also, Based on user type the questions are to be shown. Please help. If type is student then the questions are not getting displayed else condition the questions are getting displayed
What I can see is, you have mentioned wrong database when you are trying to fetch data for usertype student. Here is your code:
if (user.type === 'STUDENT' || user.type === 'student') {
console.log(user.type + 'type');
const questions = await db.find('QUESTIONG', { number: { $in: nextQuestions } });
You need to correct the database name, and everything will work fine:
const questions = await db.find('QUESTION', { number: { $in: nextQuestions } });
Hope this works!!!

Wait for mongoose.find inside foreach loop inside callback

How do I wait till data is populated in finalresult before going further?
I tried async and await but did not work as expected and on top of that I am new to nodejs express
exports.getporderlist = (req, res) => {
page = req.params.page || "1";
skip = (page - 1) * 10;
if (req.profile.role.includes(1)) {
Order.find({ status: { $in: [0, 2] } })
.select("_id updatedAt items salesman")
.populate("customer", "customer_name phone")
.sort({ updatedAt: -1 })
.skip(skip)
.limit(10)
.exec((err, orders) => {
if (err) {
return res.status(400).json({
error: "No Orders found",
});
}
let finalresult = [];
orders.forEach((oelement) => {
total = 0;
salesman = oelement.salesman.split(" ")[0];
itemscount = oelement.items.length;
placeorder = true;
oelement.items.forEach((element) => {
total += element.price * element.quantity;
});
//Wait for the bellow data variable to finish populating finalresult
const data = Design.find()
.select("_id sm lm")
.where("_id")
.in(oelement.items)
.exec((err, orders) => {
finalresult.push(orders);
console.log(orders);
});
});
console.log(1);
res.json(finalresult);//getting empty finalresult array on call
});
} else {
res.json({ Message: "Go away" });
}
};
The exec() function do returns promise, so you can user async/await to call it.
Your code will look like this:
exports.getporderlist = async (req, res) => {
try {
if (req.profile.role.includes(1)) {
page = Number(req.params.page) || 1;
skip = (page - 1) * 10;
const orders = await Order.find({
status: {
$in: [0, 2]
}
})
.select("_id updatedAt items salesman")
.populate("customer", "customer_name phone")
.sort({
updatedAt: -1
})
.skip(skip)
.limit(10)
.exec();
let finalresult = [];
for (const oelement of orders) {
let total = 0;
salesman = oelement.salesman.split(" ")[0];
itemscount = oelement.items.length;
placeorder = true;
oelement.items.forEach((element) => {
total += element.price * element.quantity;
});
const data = await Design.find()
.select("_id sm lm")
.where("_id")
.in(oelement.items)
.exec();
finalresult.push(data);
}
res.json(finalresult);
} else {
res.json({
Message: "Go away"
});
}
} catch (err) {
return res.status(400).json({
error: "No Orders found",
});
}
}
you can always call async functions with async/await inside for ..of loops. You can read more here
P.s. Couldn't get a chance to run the code.. Let me know if you have any doubts :)

store field value in cloud function variable

I need to get a value from FIRE BASE FIRESTORE and store it in a variable at the cloud function
because I want to compare two variables in an if statement, using node JS the code that I used is shown below:
exports.helloWorld = functions.https.onRequest(
(data, response) => {
const bidder = admin.firestore();
var old = bidder.collection(data['collection'])
.doc(data["doc_id"])
.get();
bidder.collection(data['collection'])
.doc(data["doc_id"])
.get()
.then(
data => {
old = data.data()['price'];
}
);
var newprice = data["new price"];
if (newprice <= old) {
return response.status(500)
.json({ message: 'Not Allowed.' });
} else {
return bidder.collection(data['collection'])
.doc(data["doc_id"])
.update(
{
name_of_bidder: data["name_of_bidder"],
price: data["price"],
phone: data["phone"],
capital: true
},
{ merge: true }
);
}
}
);
Calling get() on a Document Reference returns a Promise, so you have to wait for its end to have access to the data. I think that what you want is this:
exports.helloWorld = functions.https.onRequest(
async (data, response) => {
const bidder = admin.firestore();
var oldDocument = await bidder.collection(data['collection'])
.doc(data["doc_id"])
.get();
var old = oldDocument.data["price"];
var newprice = data["new price"];
if (newprice <= old) {
return response.status(500)
.json({ message: 'Not Allowed.' });
} else {
return bidder.collection(data['collection'])
.doc(data["doc_id"])
.update(
{
name_of_bidder: data["name_of_bidder"],
price: data["price"],
phone: data["phone"],
capital: true
},
{ merge: true }
);
}
}
);

Business logic works but Mongoose save doesn't

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 }));
}

Resources