How to use Quick sort in MERN Stack project - node.js

I have got a task where I have to use Quicksort instead of using the (MongoDB) mongoose default sort method.
I could not find any solution on how to implement it.
Current code:
export const getProduct = expressAsyncHandler(async (req, res) => {
const pageSize = req.headers.referer === DASHBOARD_SCREEN_ROUTE ? 12 : 6;
const page = Number(req.query.pageNumber) || 1;
const sortOrder =
order === 'lowest'
? { price: 1 }
: order === 'highest'
? { price: -1 }
: order === 'toprated'
? { rating: -1 }
: { _id: -1 };
const products = await Product.find({})
.sort(sortOrder)
.skip(pageSize * (page - 1))
.limit(pageSize);
try {
res.send({ products });
} catch (error) {
console.log(error);
res.status(512).send(error.message);
}
});
Instead of .sort method, I have to use quick sort there.

Related

server side pagination in node js and mongo db

please help me with this server side pagination in node js and mongo db
function getServiceQualityAnex(req, res, next) {
if (req.query.code != null) {
ServiceQualityAnex.find({ location: req.query.code }).sort({ _id: -1 }).select('-hash')
.then(serviceQualityAnexC => res.json(serviceQualityAnexC))
.catch(err => {
res.sendStatus(404);
next(err)
});
} else {
ServiceQualityAnex.find({}).sort({ _id: -1 }).select('-hash')
.then(serviceQualityAnexC => res.json(serviceQualityAnexC))
.catch(err => {
res.sendStatus(404);
next(err)
});
}
}
let page = Number(req.query.page);
page = page ? page : 0;
let limit = parseInt(req.query.limit);
const result = {};
let startIndex = page * limit;
if (startIndex > 0) {
result.previous = {
page: page - 1,
limit: limit,
};
}
let receive = await Model.find()
.sort("-_id")
.skip(startIndex)
.limit(limit)
.exec();
i want to do a server side pagination on server side my front end api is http://localhost:3000/getServiceQualityAnexJoin/ the function which is mentioned above is combing 2 tables are returning . my data is very huge and i want to add a server side pagination
You did not specify all the requirements in your question but what i precieve is that you want to do pagination on server side with nodejs in mongodb
Here is what you need to do:
const getServiceQualityAnex = async (request, response) => {
try {
const id = request.params.id;
let { page } = request.query; //this indicates the page you are requesting for in pagination
if (!page)
page = 1; //by default it is one
const result = await ServiceQualityAnex.aggregate([
{
$match: {
"_id": mongoose.Types.ObjectId(id)
}
},
{
$project: {
"_id": 1,
.
.
.
// all the fields you want to get
}
},
{
$facet: { //facet is the aggregation pipeline in mongodb through which you can achieve pagination
metadata: [{ $count: 'total' }],
data: [
{
$skip: (Number(page) - 1) * Number(20)
},
{
$limit: 20 //20 records limit per page
},
]
}
}
]);
console.log("result :", result[0].data);
return response
.status(200)
.json(
{
result: result[0].data,
meta: {
current_page: page,
total_pages: Math.ceil(
(Number(result[0].metadata.length === 0 ? 0 : result[0].metadata[0].total))
/ (Number(20))),
total_count: result[0].metadata.length === 0 ? 0 : result[0].metadata[0].total,
}
}
);
} catch (error) {
console.log(error);
response.status(500).json({
error: "Something went wrong",
});
}
}
If you don't know anything about aggregation then you must visit this site:
MongoDB aggregation framework

mongoose find multiple filters not working

Good day guys, I am trying to set up a store filtering API with node and MongoDB in the format below.
getProduct = async (req, res) => {
try {
const {
name,
category,
brand,
minPrice,
maxPrice,
minRating,
field,
sort,
} = req.query;
//queryObjects
const queryObjects = {};
if (name) {
queryObjects.name = { $regex: name, $options: 'i' };
}
// if(category){
// queryObjects.category={$regex:category,$options:'i'}
// }
// if(brand){
// queryObjects.brand={$regex:brand,$options:'i'}
// }
queryObjects.price = { $gt: minPrice, $lt: maxPrice };
queryObjects.rating = { $gt: minRating };
var result = Product.find(queryObjects);
//sorting result
if (sort) {
const sortList = sort.split(',').join(' ');
result = result.sort(sortList);
} else {
result = result.sort('rating');
}
//show specific fields
if (field) {
const fieldList = field.split(',').join(' ');
result = result.select(fieldList);
}
console.log(queryObjects);
const page = Number(req.query.page);
const limit = Number(req.query.limit);
const skip = (page - 1) * limit;
result = result.skip(skip).limit(limit);
const products = await result;
res.send({ data: products });
} catch (error) {
res.send(error);
}
};
when I make a request(get) I get an empty array as my responsepostman response
when I log queryObject in the console I getqueryObject
everything works when I add the filters one by one.
what am I doing wrong and how can I pass in multiple filters to the find method in mongoose.
Please help, thanks

why i am getting this error ? "Query was already executed: Product.find({ price: { '$lte': 1000, '$gte': 1 } })"

I am fetching API request from my frontend as I am using reactjs
When I try to filter product by price I am getting unexpected error:
axios call
axios.get(`/api/v1/products?keyword=${keyword}&page=${currentPage}&price[lte]=${price[1]}&price[gte]=${price[0]}`)
Backend
In my backend i am handling the get request as
exports.getProducts = (req, res, next) => {
const resPerPage = 4;
const productsCount = await Product.countDocuments();
const apiFeatures = new APIFeatures(Product.find(), req.query)
.search()
.filter();
let products = await apiFeatures.query;
let filteredProductsCount = products.length;
apiFeatures.pagination(resPerPage);
products = await apiFeatures.query;
res.status(200).json({
success: true,
productsCount,
resPerPage,
filteredProductsCount,
products,
});
};
and my APIFeatures.js is
class APIFeatures {
constructor(query, queryStr) {
this.query = query;
this.queryStr = queryStr;
}
search() {
const keyword = this.queryStr.keyword
? {
name: {
$regex: this.queryStr.keyword,
$options: 'i',
},
}
: {};
this.query = this.query.find({ ...keyword });
return this;
}
filter() {
const queryCopy = { ...this.queryStr };
// removing fields from the query
const removeFields = ['keyword', 'limit', 'page'];
removeFields.forEach((el) => delete queryCopy[el]);
// advance filter for price, ratings etc
let queryStr = JSON.stringify(queryCopy);
queryStr = queryStr.replace(/\b(gt|gte|lt|lte)\b/g, (match) => `$${match}`);
this.query = this.query.find(JSON.parse(queryStr));
return this;
}
pagination(resPerPage) {
const currentPage = Number(this.queryStr.page) || 1;
const skip = resPerPage * (currentPage - 1);
this.query = this.query.limit(resPerPage).skip(skip);
return this;
}
}
module.exports = APIFeatures;
But when i dispatch get request from my frontend i am getting error about my price filter
Error
"Query was already executed: Product.find({ price: { '$lte': 1000, '$gte': 1 } })"
https://mongoosejs.com/docs/migrating_to_6.html#duplicate-query-execution
products = await apiFeatures.query.clone();
hey I was facing the same issue
a quick fix for this is to use clone when you are executing the query again.
like this:-
products = await apiFeature.query.clone();
use this
const apiFeatures = new APIFeatures(Product.find().exec(), req.query)
.search()
.filter();
This worked for me
let products = await apiFeatures.query.clone();

How to read `JSON` object in Angular

I have a API in my Node app like this:
exports.getPlanningStages = async (req, res, next) => {
const currentPage = req.query.page || 1;
const perPage = 10;
try {
const totalItems = await Planningstage.find().countDocuments();
const planningstages = await Planningstage.find()
.populate("creator")
.sort({ createdAt: -1 })
.skip((currentPage - 1) * perPage)
.limit(perPage);
// res.status(200).json(planningstages);
res.status(200).json({
planningstages,
totalItems: totalItems,
});
} catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};
And this is my HTTP request in Angular:
fetch() {
this.psService.getPlanningStages().subscribe((resData) => {
console.log(resData);
});
}
This is the response of my request: console.log
How can I split this json into two separate variables?
Try using ES6 Destructuring assignment feature like this:
fetch() {
this.psService.getPlanningStages().subscribe((resData) => {
const [planningstages, totalitems] = resData;
});
}

Confusion in Query API of mongoose

Can anyone please tell me why the given below code(PART-1) works fine whereas gives error that posts.skip is not a function? in PART-2
I am wondering that why in PART-1 code it returned Query instance whereas I am getting an array of posts.
PART-1
const query = MyModel.find(); // `query` is an instance of `Query`
query.setOptions({ lean : true });
query.collection(MyModel.collection);
query.where('age').gte(21).exec(callback);
PART-2
const posts = await PostModel.find({});
posts.skip((page - 1) * 10).limit(10);
Basically I am trying to refactor this code so that I don't have to each time use pagination logic and achieve that by writing a pagination util function where the function will have first params a Query instance of mongoose
getAllPost: async (req, res, next) => {
const pagination = req.query.pagination ? parseInt(req.query.pagination) : 10
const currentPage = req.query.page ? parseInt(req.query.page) : 1
try {
const posts = await PostModel.find({}).lean()
.skip((currentPage - 1) * pagination)
.limit(pagination)
.populate('userId', ['name.firstName', 'name.lastName', 'email', 'isAdmin'])
.sort({ updatedAt: -1 })
.exec()
if (!posts.length) {
return res.status(HttpStatus.NOT_FOUND).json({ message: 'No posts found' })
}
return res.status(HttpStatus.OK).json({ posts: posts })
} catch (error) {
HANDLER.handleError(res, error)
}
},
Util function like: (For example)
module.exports = {
paginate: async (req, query, next) => {
const options= {
pagination: req.query.pagination ? parseInt(req.query.pagination) : 10,
currentPage: req.query.page ? parseInt(req.query.page) : 1
}
query.skip((currentPage-1)*pagination).limit(pagination)
query.exec((err, result)=>{ return result; })
}
}
I finally fixed this by implementing this paginate helper:
i.e /utils/paginate.js
module.exports = {
paginate: (req) => {
const query = {}
const pagination = req.query.pagination ? parseInt(req.query.pagination) : 10
const currentPage = req.query.page ? parseInt(req.query.page) : 1
query.skip = (currentPage - 1) * pagination
query.limit = pagination
return query
}
}
and use this helper function to paginate, by apssing as an argument to .find() in mongoose, for example:
const helper = require('../utils/paginate');
getAllPost: async (req, res, next) => {
try {
const posts = await PostModel.find({}, {}, helper.pagnate(req)).lean()
.populate('userId', ['name.firstName', 'name.lastName', 'email', 'isAdmin'])
.sort({ updatedAt: -1 })
.exec()
if (!posts.length) {
return res.status(HttpStatus.NOT_FOUND).json({ message: 'No posts found' })
}
return res.status(HttpStatus.OK).json({ posts: posts })
} catch (error) {
HANDLER.handleError(res, error)
}
}

Resources