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