When i push value to empty array it showing Node js - node.js

exports.OrderPlace = (req, res) => {
const all_product = req.body.product_info;
let meta = [];
all_product.forEach((element) => {
Ticket.find({ _id: element.product_id }, function (err, docs) {
if (err) return handleError(err);
if (docs[0]._id == element.product_id) {
if (element.quantity < docs[0].quantity) {
meta.push({
cart_id: element.id,
pro_id: element.product_id,
quantity: element.quantity + " Asking quentity is not available!",
});
}
}
});
});
console.log(meta);
};
I'm trying to push cart_id , pro_id, quantity. its loging me empty value please help
Im expecting console.log(meta) values like
[
{
cart_id: "63db8665ba7126c2b35fb231",
pro_id: "63d025a8eefcf49cdcdd5472",
quantity: "36 Asking quentity is not available!",
},
{
cart_id: "63dbc2a7fbf7daf48052189e",
pro_id: "63ce4393c3433881173d1502",
quantity: "40 Asking quentity is not available!",
}
]

wrap the whole code block inside an async function, and use await inside the function to wait for the result of the Ticket.find operation.
exports.OrderPlace = async (req, res) => {
const all_product = req.body.product_info;
let meta = [];
let flag = "";
for (const element of all_product) {
const docs = await Ticket.find({ _id: element.product_id }).exec();
if (docs[0]._id == element.product_id) {
if (element.quantity > docs[0].ticket_quantity) {
flag = "false";
meta.push({
cart_id: element.id,
pro_id: element.product_id,
quantity: element.quantity + " Asking quentity is not available!",
});
}
}
}
console.log({ flag: flag, meta });
};

The easiest way that I found to manipulate the array of objects is using the array methods like filter, map etc...
Maybe following code helps you
exports.OrderPlace = (req, res) => {
const all_product = req.body.product_info;
let meta = [];
all_product.forEach((element) => {
Ticket.find({ _id: element.product_id }, function (err, docs) {
if (err) return handleError(err);
element = element.filter((item) => {
return (docs[0]._id == element.product_id && element.quantity < docs[0].quantity)
})
meta = element.map((item) => {
return {
cart_id: element.id,
pro_id: element.product_id,
quantity: element.quantity + " Asking quentity is not available!",
}
});
});
});
console.log(meta);
};

Related

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!!!

Mongoose exec() does not await properly

For some reason, exec() is not awaiting in my code:
let team = <SOME TEAM NAME> //putting manually for testing
let results = []
TeamModel.find({ name: team })
.exec(async (err, docs) => {
if (err)
return res.send(Response("failure", "Error occured while retrieving fixtures"))
for(let i = 0; i < docs.length; i++){
let doesExist = await FixtureModel.exists({ leagueName: docs[i].leagueName })
if (doesExist) {
let query = FixtureModel.find({ leagueName: docs[i].leagueName, $or: [{ homeTeam: team }, { awayTeam: team }] })
await query.exec((err2, docs2) => {
if (err2)
return res.send(Response("failure", "Error occured while retrieving fixtures"))
docs2.forEach((doc2, index) => {results.push(doc2.toObject())})
console.log('during await') //Executes second
})
console.log('after await') //Executes first
}
else { //This section is not required
let result = await Communicator.GetFixturesFromLeague(docs[i].leagueId)
result.api.fixtures.forEach((fixture, index) => {
let newFixture = new FixtureModel({
fixtureId: fixture.fixture_id,
leagueId: fixture.league_id,
leagueName: fixture.league.name,
eventDate: fixture.event_date,
statusShort: fixture.statusShort,
homeTeam: fixture.homeTeam.team_name,
awayTeam: fixture.awayTeam.team_name
})
newFixture.save()
results.push(newFixture.toObject())
})
}
}
console.log(results)
res.send(Response("success", "Retrieved fixtures", results))
})
and the result looks something like this:
after await
[]
during await
and therefore an empty array of results is sent before values are added inside. I'm not sure what I'm missing here.
This is a workaround if anyones wondering. Sending the response inside the exec() callback when the forLoop completes bypassing the need for async/await.
if (doesExist) {
let query = FixtureModel.find({ league_name: docs[i].leagueName, $or: [{ homeTeam: { team_name: team} }, { awayTeam: { team_name: team} }] })
await query.exec((err2, docs2) => {
if (err2)
return res.send(Response("failure", "Error occured while retrieving fixtures"))
docs2.forEach((doc2, index) => {results.push(doc2.toObject())})
if(i + 1 == docs.length){
return res.send(Response("success", "Retrieved fixtures", results))
}
})
}

can't use the results of a mongoose query when called from another function

I'm writing a blog engine using express, and ran into a problem when trying to run a mongoose query through a function:
What I'm trying to do is to obtain a variable that contains the next and previous blog posts by id, to do that I wrote this function:
middleware.getAdjacentPosts = async function(_id) {
var adjacentPosts = {}
await Post.findOne({ _id: { $gt: _id } }).sort({ _id: 1 }).exec(async function(err, nextPost) {
if (err) {
console.log(err)
} else {
if (nextPost == null) {
adjacentPosts.nextPost = false;
} else {
adjacentPosts.nextPostUrl = nextPost.slug;
adjacentPosts.nextPostTitle = nextPost.title;
}
await Post.findOne({ _id: { $lt: _id } }).sort({ _id: -1 }).exec(
async function(err, previousPost) {
if (err) {
console.log(err.message);
} else {
if (previousPost == null) {
adjacentPosts.previousPost = false;
} else {
adjacentPosts.previousPostUrl = previousPost.slug;
adjacentPosts.previousPostTitle = previousPost.title;
}
console.log(adjacentPosts)
return adjacentPosts
}
})
}
})
}
Before returning, I can see the variable completed with what I need through the console.log. The problem I have is that when I try to execute the function, the receiving variable is empty. This would be executed in the get route for a post, like the following:
Router.get("/posts/:slug", async function(req, res) {
await Post.findOne({ slug: req.params.slug }).populate('categories').populate('comments').exec(async function(err, foundBlog) {
if (err) {
console.log(err.message)
} else {
var posts = {}
posts = await middleware.getAdjacentPosts(foundBlog._id)
console.log(posts)
res.render("frontoffice/post", {
blog: foundBlog,
postUrl: req.params.slug,
adj: posts,
reCaptchaSiteKey: process.env.CAPTCHA_SITE_KEY
})
}
})
})
Any clues of what I might be doing wrong?
As #LucaKiebel suggests, you will need to return the results from your findOnes:
middleware.getAdjacentPosts = async function(_id) {
var adjacentPosts = {};
return await Post.findOne({ _id: { $gt: _id } })
.sort({ _id: 1 })
.exec(async function(err, nextPost) {
if (err) {
console.log(err);
} else {
if (nextPost == null) {
adjacentPosts.nextPost = false;
} else {
adjacentPosts.nextPostUrl = nextPost.slug;
adjacentPosts.nextPostTitle = nextPost.title;
}
return await Post.findOne({ _id: { $lt: _id } })
.sort({ _id: -1 })
.exec(async function(err, previousPost) {
if (err) {
console.log(err.message);
} else {
if (previousPost == null) {
adjacentPosts.previousPost = false;
} else {
adjacentPosts.previousPostUrl = previousPost.slug;
adjacentPosts.previousPostTitle = previousPost.title;
}
console.log(adjacentPosts);
return adjacentPosts;
}
});
}
});
};
A potential improvement, since you are using async/await anyway, might be to get rid of the callbacks:
middleware.getAdjacentPosts = async function(_id) {
var adjacentPosts = {};
try {
const nextPost = await Post.findOne({ _id: { $gt: _id } }).sort({ _id: 1 });
if (nextPost == null) {
adjacentPosts.nextPost = false;
} else {
adjacentPosts.nextPostUrl = nextPost.slug;
adjacentPosts.nextPostTitle = nextPost.title;
}
const previousPost = await Post.findOne({ _id: { $lt: _id } }).sort({ _id: -1 })
if (previousPost == null) {
adjacentPosts.previousPost = false;
} else {
adjacentPosts.previousPostUrl = previousPost.slug;
adjacentPosts.previousPostTitle = previousPost.title;
}
console.log(adjacentPosts);
return adjacentPosts;
} catch (err) {
console.log(err);
}
};
``

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

Unable to retrive data and push inside loop in node js

I am trying to retrieve attendance list along with user details.
I am using caminte.js(http://www.camintejs.com/) Cross-db ORM for database interaction.
Here is my code sample of model function "attendanceList".
exports.attendanceList = function (req, callback) {
var query = req.query;
var searchfilters = {};
if(!req.user){
callback({ code:400, status:'error', message: 'Invalid Request', data:{}});
}else{
searchfilters["vendor_id"] = parseInt(req.user._id);
}
if(query.location && parseString(query.location) != '') {
searchfilters["location"] = parseString(query.location);
}
if (query.device_details && parseString(query.device_details) != '') {
searchfilters["device_details"] = parseString(query.device_details);
}
if(query.created_on) {
searchfilters["created_on"] = query.created_on;
}
if(query.status) {
searchfilters["status"] = { regex: new RegExp(query.status.toLowerCase(), "i") };
}
var SkipRecord = 0;
var PageSize = 10;
var LimitRecord = PageSize;
var PageIndex = 1;
if(query.pagesize) {
PageSize = parseInt(query.pagesize);
}
if(query.pageindex) {
PageIndex = parseInt(query.pageindex);
}
if (PageIndex > 1) {
SkipRecord = (PageIndex - 1) * PageSize;
}
LimitRecord = PageSize;
var SortRecord = "created_on";
if(query.sortby && query.sorttype) {
var sortingBy = query.sortby;
var sortingType = 'ASC';
if(typeof query.sorttype !== 'undefined') {
sortingType = query.sorttype;
}
SortRecord = sortingBy + ' ' + sortingType;
}
Attendance.find({ where: searchfilters, order: SortRecord, limit: LimitRecord, skip: SkipRecord }, async function (err, result) {
if(err){
callback({ code:400, status:'error', message:'Unable to connect server', errors:err });
} else {
await result.map(function(row, i){
User.findById(parseInt(row.user_id), function(err, data){
if(err){
console.log(err);
} else {
result[i]['userDetails'] = data;
}
});
});
await Attendance.count({ where: searchfilters }, function (err, count) {
callback({ code:200, status:'success', message:'OK', total:count, data:result });
});
}
});
};
I am getting only attendance list without user details. How do I force to push user details into attendance list? Any Help!!
Thank You
This behavior is asynchronous. When you're making request to DB, your code keeps running, while task to get data comes to task queue.
To keep things simple, you need to use promises while handling asynchronous jobs.
Rewrite your code from this:
Attendance.find({ where: searchfilters, order: SortRecord, limit: LimitRecord, skip: SkipRecord }, async function (err, result) {
if(err){
callback({ code:400, status:'error', message:'Unable to connect server', errors:err });
} else {
await result.map(function(row, i){
User.findById(parseInt(row.user_id), function(err, data){
if(err){
console.log(err);
} else {
result[i]['userDetails'] = data;
}
});
});
await Attendance.count({ where: searchfilters }, function (err, count) {
callback({ code:200, status:'success', message:'OK', total:count, data:result });
});
}
});
To this:
const findAttendanceFirst = (searchFilters, SortRecord, LimitRecord, SkipRecord) => {
return new Promise((resolve, reject) => {
Attendance.find({ where: searchFilters, order: SortRecord, limit: LimitRecord, skip: SkipRecord }, (err, result) => {
if(err) return reject(err);
resolve(result);
});
});
}
const findUserByIdForUserDetails = (userId) => {
return new Promise((resolve, reject) => {
User.findById(parseInt(userId), function(err, data){
if(err) return reject(err);
resolve(data);
})
});
}
const getAttendanceCount = (searchFilters) => {
return new Promise((resolve, reject) => {
Attendance.count({ where: searchFilters }, (err, count) => {
if(err) return reject(err);
resolve(count);
});
})
}
So, now we can use this separate functions to make async behavior looks like sync.
try {
const data = await findAttendanceFirst(searchFilters, SortRecord, LimitRecord, SkipRecord);
for(let userData of data){
try {
userData.userDetails = await findUserByIdForUserDetails(userData.user_id);
} catch(e) {
// Some error happened, so no user details.
// you can set here null or nothing to userDetails.
}
}
let count;
try {
count = await getAttendanceCount(searchFilters);
} catch(e){
// Same as before.
}
const callBackData = { code:200, status:'success', message:'OK', total:count, data:result };
// And here you can do whatever you want with callback data. Send to client etc.
} catch(e) {
}
NB: I've not tested this code, it will be easier for yu to play with your actual data and use Promises and async/await
Just remember that each request to db is asynchronous, and you need to make your code wait for this data.

Resources