Pass multiple queries in GET request to mongodb - node.js

// route.js
const express = require('express');
const router = express.Router();
const userHandler = require('../handler/user');
router.get('',userHandler.getUser);
module.exports = route
-
// Handler.js
const userController = require('../../core/controller/user');
// get user
getUser = async (req, res, next) => {
//console.log(req)
try {
let user = await userController.getUser(req.params.id, req.query.employeeStatus, req.query.department)
req.data = user
next()
}
catch (e) {
req.status = 400;
next(e)
}
}
module.exports = {getUser}
-
// controller.js
exports.getUser = async (userId,employeeStatus,department) => {
let userRecords = await userModel.getUser(userId,employeeStatus,department);
userRecords = userRecords.map(it => {
return {
id: it._id,
firstName: it.firstName,
lastName: it.lastName,
pic: it.pic,
gender: it.gender,
dob: it.dob,
maritalStatus: it.maritalStatus,
nationality: it.nationality,
streetAddress: it.streetAddress,
city: it.city,
state: it.state,
postalCode: it.postalCode,
country: it.country,
phone: it.phone,
email: it.email,
jobTitle: it.jobTitle,
department: it.department,
dateOfJoining: it.dateOfJoining,
employeeStatus: it.employeeStatus,
kra: it.kra,
assignedSupervisor: it.assignedSupervisor,
assignedSubordinate: it.assignedSubordinate,
workExperience: it.workExperience,
skills: it.skills,
password: it.password
}
})
return userRecords;
}
-
// query.js
exports.getUser = async(userId, employeeStatus, department) => {
var whereClause = '';
if (department) {
var whereClause ={ "department":department}
console.log(whereClause)
console.log( Object.keys(whereClause).length)
}
if(userId) return await model.find({"_id":userId}).exec();
if (employeeStatus){
console.log('debewbfewhfui')
if ( Object.keys(whereClause).length) {
console.log(whereClause)
whereClause += ','
console.log( whereClause.toSource())
console.log(whereClause.hasOwnProperty("employeeStatus"))
whereClause += {"employeeStatus":employeeStatus}
}
console.log(whereClause)
//whereClause = {"employeeStatus":employeeStatus}
console.log('e', Object.keys(whereClause).length)
// }])
// console.log(department)
// return await model.find({ $and: [ { $or: [{"employeeStatus": employeeStatus }] },{"department": department} ] }).exec();
// return await model.find({"employeeStatus":employeeStatus}).find({"department":department}).exec();
}
// if(department) {
// console.log('55')
// return await model.find({"department":department}).exec();
// };
// if (Object.keys(whereClause).length) {
// console.log(whereClause)
// whereClause = whereClause + ','
// }
var query = await model.find({$and : [whereClause] }).exec();
console.log('fssd',JSON.stringify(whereClause))
return query
}
I want if we pass any data department or employeestatus in query it will return data as required and if we dont pass any query then it will search all users. Can anyone help me please?

To conditionally compose the query filters depending on the parameters passed into the function, this should work:
query.js
exports.getUser = async (userId, employeeStatus, department) => {
let queryFilters = { userId, employeeStatus, department };
// The JSON stringify and parsing below would help remove undefined filter values
// i.e if userId is not provided, while employeeStatus and department are given
// the queryFilters object would only contain employeeStatus and department.
queryFilters = JSON.parse(JSON.stringify(queryFilters))
return model.find(queryFilters);
}

Related

Path `comment` is required. MERN stack

I don't understand why I get this error. This is my controller:
export const createProductReview = async (req, res) => {
const { rating, comment } = req.body;
const product = await Product.findById(req.params.id);
if (product) {
const alreadyReviewed = product.reviews.find(
r => r.user.toString() === req.user.userId.toString()
);
if (alreadyReviewed) {
throw new NotFoundError('Product already reviewed');
}
const review = {
user: req.user.userId,
name: req.user.username,
rating: Number(rating),
comment,
};
product.reviews.push(review);
product.numOfReviews = product.reviews.length;
product.rating =
product.reviews.reduce((acc, item) => item.rating + acc, 0) /
product.reviews.length;
await product.save();
res.status(StatusCodes.OK).json({ message: 'Review added', review });
} else {
throw new NotFoundError('Product not found');
}
};
This is mine productPage where i dispatch addProductReview and passing product id from params and review object:
const [rating, setRating] = useState(0);
const [comment, setComment] = useState('');
const submitHandler = e => {
e.preventDefault();
dispatch(
addProductReview(id, {
rating,
comment,
})
);
};
And this is my productSlice:
export const addProductReview = createAsyncThunk(
'product/review',
async (id, { review }, thunkAPI) => {
try {
const { data } = await axios.post(
`/api/v1/products/${id}/reviews`,
review
);
return data;
} catch (error) {
const message = error.response.data.msg;
return thunkAPI.rejectWithValue(message);
}
}
);
I have no clue why i got error Path comment is required. i pass review object to route.
The issue is with the parameters used in your Thunk payloadCreator. From the documentation...
The payloadCreator function will be called with two arguments:
arg: a single value, containing the first parameter that was passed to the thunk action creator when it was dispatched. This is useful for passing in values like item IDs that may be needed as part of the request. If you need to pass in multiple values, pass them together in an object when you dispatch the thunk, like dispatch(fetchUsers({status: 'active', sortBy: 'name'})).
thunkAPI: an object containing all of the parameters that are normally passed to a Redux thunk function, as well as additional options
Your payloadCreator has three arguments which is incorrect.
Try this instead
export const addProductReview = createAsyncThunk(
'product/review',
async ({ id, ...review }, thunkAPI) => {
try {
const { data } = await axios.post(
`/api/v1/products/${id}/reviews`,
review
);
return data;
} catch (error) {
const message = error.response.data.msg;
return thunkAPI.rejectWithValue(message);
}
}
);
and dispatch it like this
dispatch(addProductReview({ id, rating, comment }));

UpdateOne is not working Express and Mongodb

I am trying to update a content in Mongodb with the help of function UpdateOne but I keep getting "0 document(s) matched the filter, updated 0 document(s)". I am not sure what I am doing wrong here.
In the end you can see the attached picture from postman where I am sending the request
doucumnets.js
const database = require('../db/database.js');
const ObjectId = require('mongodb').ObjectId;
const documents = {
updateDoc: async function updateDoc(id, newContent) {
let db;
try {
db = await database.getDb();
const filter = { _id: ObjectId(id) };
const options = { upsert: false };
// // const query = {_id: "633abe851b36b295c11f74b5"};
// // const update = { $set: { contents: "Updated!!!"}};
const updatedDoc = {
$set: {
"contents": newContent
},
};
// console.log(filter);
// const result = await db.collection.updateOne( id, newContent, options );
const result = await db.collection.updateOne( filter, updatedDoc, options );
console.log(
`${result.matchedCount} document(s) matched the filter, updated ${result.modifiedCount} document(s)`,
);
return result;
} catch (error) {
return {
errors: {
message: error.message
}
};
} finally {
await db.client.close();
// console.log(db.close());
}
},
};
module.exports = documents;
route/index.js
const express = require('express');
const router = express.Router();
const documentsModel = require('../models/documents.js');
router.put("/update", async(req, res) => {
try {
const oldId = req.body.id;
const newContent = req.body.newContent;
const result = await documentsModel.updateDoc(oldId, newContent);
return res.status(201).json({ data: result});
} catch (errors) {
console.error(errors.message);
res.send(400).send('Problem with server');
}
});
module.exports = router;

mongoose findById return null

I'm doing a to do list application. I use the following function to move a task in the to-do list to the done list. However, the "columnId" method I use as the url parameter and the "findById" method that I use return null. What do you think the problem might be?
public async Put(columnId: string, todo: ITodo): Promise<ITodo | null> {
try {
const editingTodo: ITodo | null = await Todo.findById(todo._id);
if (editingTodo !== null) {
const oldColumn: IColumn | null = await Column.findById(editingTodo.Column._id).exec();
if (oldColumn !== null) {
const todoIndexByOldColumn = oldColumn.Todos.indexOf(editingTodo._id);
oldColumn.Todos.splice(todoIndexByOldColumn, 1);
const newColumn: IColumn | null = await Column.findById(columnId).populate("Todos").exec();
console.log(newColumn);
if (newColumn !== null) {
newColumn.Todos.push(todo);
newColumn.save();
oldColumn.save();
editingTodo.save();
}
}
}
return editingTodo;
} catch (error) {
throw error;
}
}
Here is crud operation for a todo list with mongoose.
// model todo
let todo = new schema({
description: { type: String },
heading: { type: String },
title: { type: String },
});
Below is the controller with logic for all operations.
// get All Todo List
let findAllTodoList = async (req, res, next ) => {
let foundAllTodo = await todo.findAll({});
res.send({ data: foundAllTodo });
};
// get Specific Todo
let findTodoById = async (req, res, next ) => {
let todo_id = req.params.todo_id;
let foundTodo = await todo.findById(todo_id);
res.send({ data: foundTodo });
};
// create Todo Element
let createTodo = async (req, res, next ) => {
let todo_obj = {
description: 'Here Add Element',
heading: 'Adding',
title: 'Add',
};
let foundTodo = await todo.create(todo_obj);
res.send({ data: 'success' });
};
// Destroy Todo Element
let DeleteTodoById = async (req, res, next ) => {
let todo_id = req.params.todo_id
let foundTodo = await todo.remove({ _id:todo_id });
res.send({ data: 'success' });
};
module.exports = {
findAllTodoList
findTodoById,
createTodo,
DeleteTodoById
};

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

Node JS Promise.all and forEach in nested Array

In a Node app with typescript, i need to iterate through a array and i call an asynchronous function inside the loop to get informations about the related items for each item in the array. The function is called for each related item to get its title in relatedItems array.
I'm able to retrieve promises for the 2nd level array (relatedItems) but not sure how to implement a then once top level finishes as well.
How to reach my goal with promise.all.
var Inputarray = [
{ Category: "cat1"
relatedItems: [
{id: "1"},
{id: "2"},
{id: "3"}
]
},
{
Category: "cat2"
relatedItems: [
{id: "1"},
{id: "2"},
{id: "3"}
]
}
];
var wantedresult= [
{ Category: "cat1"
relatedItems: [
{Title: "xxx"},
{Title: "yyy"},
{Title: "zzz"}
]
},
{
Category: "cat2"
relatedItems: [
{Title: "ttt"},
{Title: "kkk"},
{Title: "mmm"}
]
}
];
private GetAllRelattedItems(data: IListItem[]): any{
let rendredItems: RelatedItem[] = new Array();
data.forEach(item => {
let relatedItemsinfos : relatedItemInfos[]=item.Children;
let localTab:relatedItem[]=new Array();
let newItem = {
Category:item.Category,
Children: []
};
var promises = [];
relatedItemsinfos.forEach(relatedItemsInfositem =>{
promises.push(this.GetRelatedItem(relatedItemsInfositem.WebId,relatedItemsInfositem.ListId,relatedItemsInfositem.ItemId));
});
Promise.all(promises).then(function(response) {
response.forEach(obj=>{
let newNode: relatedItem ={
Title :Obj.Title,
};
newItem.Children.push(newNode);
});
rendredItems.push(newItem);
});
});
}
private GetRelatedItem(id:string) : Promise<relatedItem> {
return new Promise((resolve) => {
pnp.sp.site.openWeb()
.then(web => {
//this.getWeb()
//.then((web) => {
return web.web.lists.getList().get(); //w.web.lists.getById("").get().then(r => {
})
.then((list) => {
return this.getItem(list,id);
})
.then((item) => {
resolve(item);
});
});
}
You should use Promise.all at the top level and return the promise for each item in the data array:
private GetAllRelattedItems(data: IListItem[]): any {
//..
let allData = data.map(item => {
//..
return Promise.all(promises).then(function (response) {
//..
});
});
Promise.all(allData).then (_=> { /* After all data is retrieved */})
}
Since you are using Typescript a better approach would be to take advantage of async/await to make the code more readable:
private async GetAllRelattedItems(data: IListItem[]): Promise<RendredItem[]> {
let allData = data.map(async item => {
let relatedItemsinfos: relatedItemInfos[] = item.Children;
let localTab: relatedItem[] = new Array();
let newItem = {
Category: item.Category,
Children: []
};
var response = await Promise.all(relatedItemsinfos.map(relatedItemsInfositem => {
return this.GetRelatedItem(relatedItemsInfositem.WebId);
}));
newItem.Children = response.map(entry => ({
Title: entry.value[0].Title,
FileLeafRef: entry.value[0].FileLeafRef,
Modified: entry.value[0].Modified,
FileRef: entry.value[0].FileRef,
FieldValuesAsText: {
FileRef: entry.value[0].FileRef,
}
}));
return newItem;
});
var result = await Promise.all(allData);
// After all results are done
return result
}
private async GetRelatedItem(id: string): Promise<{ value: relatedItem[] }> {
const web = await pnp.sp.site.openWeb()
const list = await web.web.lists.getList().get(); //w.web.lists.getById("").get().then(r => {
return await this.getItem(list,id);
}
// Placeholder
public getItem(list: any[], id: string ): Promise<{ value: relatedItem[] }>{
return Promise.resolve({
value : []
});
}
Note I guessed some of the types based on usage, you should review to make sure they are correct.
private async GetAllRelattedItems(data: IListItem[]): Promise<RendredItem[]> {
let allData = data.map(async item => {
let relatedItemsinfos: relatedItemInfos[] = item.Children;
let localTab: relatedItem[] = new Array();
let newItem = {
Category: item.Category,
Children: []
};
var response = await Promise.all(relatedItemsinfos.map(relatedItemsInfositem => {
return this.GetRelatedItem(relatedItemsInfositem);
}));
newItem.Children = response.map(entry => ({
Title: entry.value[0].Title,
FileLeafRef: entry.value[0].FileLeafRef,
Modified: entry.value[0].Modified,
FileRef: entry.value[0].FileRef,
FieldValuesAsText: {
FileRef: entry.value[0].FileRef,
}
}));
return newItem;
});
var result = await Promise.all(allData);
// After all results are done
return result
}
private async GetRelatedItem(relatedItemsInfositem) : Promise<any> {
const web = await pnp.sp.site.openWebById(relatedItemsInfositem.WebId);
const list = await web.web.lists.getById(relatedItemsInfositem.ListId).get();
return await this.getItem(list,relatedItemsInfositem.ItemId);
// here i would like to call GetItemSize that is async and that take return the size as a number but i would like to return the whole item model
}
public getItem(list: any, itemId: string): Promise<any>{
let url: string;
if(list.ParentWebUrl !='/'){
url= list.ParentWebUrl + "/_api/web/lists/getbytitle('"+list.Title+"')/items?$select=FileLeafRef,FileRef,Title,File/ServerRelativeUrl,Modified,FieldValuesAsText/FileRef&$expand=File&$expand=FieldValuesAsText&$filter=Id eq "+itemId;
}
else url="/_api/web/lists/getbytitle('"+list.Title+"')/items?$select=FileLeafRef,FileRef,Title,File/ServerRelativeUrl,Modified,FieldValuesAsText/FileRef&$expand=FieldValuesAsText&$expand=File&$filter=Id eq "+itemId;
return this.context.spHttpClient.get(url,SPHttpClient.configurations.v1).then((response: Response)=>{
return response.json();
});
}
private async GetItemSize(title: string): Promise<relatedItem>{
let url:string ;
let response‌​ = await this.context.spHttpClient.get(url ,SPHttpClient.configuration‌​s.v1);
// Asuming the json has the shape of relatedItem : Here the response is just a number and not shaped RelatedItem the goal is to return the whole relatedItem with size information.
return <relatedItem>response.json(); }

Resources