We got query conditions at once. so we should divide process of querying.
Find resource(query) -> Select -> Sort -> pagination
Below code is advanced query I learned in my udemy course. I need to understand this line by line.
so dive in to this code.
const advancedResults = (model, populate) => async (req, res, next) => {
let query;
// Copy req.query
const reqQuery = { ...req.query };
// Fields to exclude
const removeFields = ['select', 'sort', 'page', 'limit'];
// Loop over removeFields and delete them from reqQuery
removeFields.forEach(param => delete reqQuery[param]);
// Create query string
let queryStr = JSON.stringify(reqQuery);
// Create operators ($gt, $gte, etc)
queryStr = queryStr.replace(/\b(gt|gte|lt|lte|in)\b/g, match => `$${match}`);
// Finding resource
query = model.find(JSON.parse(queryStr));
// Select Fields
if (req.query.select) {
const fields = req.query.select.split(',').join(' ');
query = query.select(fields);
}
// Sort
if (req.query.sort) {
const sortBy = req.query.sort.split(',').join(' ');
query = query.sort(sortBy);
} else {
query = query.sort('-createdAt');
}
// Pagination
const page = parseInt(req.query.page, 10) || 1;
const limit = parseInt(req.query.limit, 10) || 25;
const startIndex = (page - 1) * limit;
const endIndex = page * limit;
const total = await model.countDocuments(JSON.parse(queryStr));
query = query.skip(startIndex).limit(limit);
if (populate) {
query = query.populate(populate);
}
// Executing query
const results = await query;
// Pagination result
const pagination = {};
if (endIndex < total) {
pagination.next = {
page: page + 1,
limit
};
}
if (startIndex > 0) {
pagination.prev = {
page: page - 1,
limit
};
}
res.advancedResults = {
success: true,
count: results.length,
pagination,
data: results
};
next();
};
module.exports = advancedResults;
How does 'advancedResult' process.
1. Copy req.query in a variable
2. Exclude fields which dont need at find() method. ('select', 'sort', etc)
3. Create queryString and modify to mongoose can understands( in => $in, gt => $gte)
4. Query with modified queryString
5. and then with query Results, do select, sort, populate etc
At first, when we call "advancedResults", we provide 'model' and 'populate'
router
.route('/')
.get(advancedResults(Model, 'populate'), getCourses);
Searching what we want in query(Filtering from the model)
1. Copy req.query in a variable(reqQuery)
2. Stringify requset / we need request as a string to manipuate and then append '$' to the matched variable
3. Replace arguments(put '$', gt => $gte, in => $in)
4. Change stringified request to JSON back.
const advancedResults = (model, populate) => async (req, res, next) => {
let query;
1) let queryStr = JSON.stringify(req.query);
2) queryStr = queryStr.replace(/b(gt|gte|lt|lte|in)\b/g, match => `$${match}`);
3) query = Course.find(JSON.parse(queryStr));
4) const courses = await query;
If we request below.
// if we have fieldA in course
GET /api/v1/courses?fiedsA[lte]=10000
Server got above request as JSON object below.
{ fieldsA: { lte: 10000 } }
Then by the advancedResults it will be changed to
{ fieldA: { $lte: 10000 }}
So, mongoose can query this lte.
Next, we do "select" what we will send to front and what order we will show /"sort"
Selecting and Sorting is next step after searching data. so we should remove this variables in finding condition.
let query;
const reqQuery = { ...req.query };
// Fields to exclude
+ const removeFields = ['select', 'sort']; [ 1 ]
// Loop over removeFields and delete them from reqQuery
+ removeFields.forEach(param => delte reqQuery[param]); [ 2 ]
let queryStr = JSON.stringify(reqQuery);
query = model.find(JSON.parse(queryStr));
// Select Fields
+ if (req.query.select) {
+ const fields = req.query.select.split(',').join(' '); [ 3 ]
+ query = query.select(fields);
+}
[ 1 ] Delete parameters that is unrelated with searching(seletc, sort etc)
[ 2 ] Then do finding in model. "model.find()"
[ 3 ] Then do works what we already deletes. selecting, sorting.
So what we need to do is basically create our own version of request stock query and pull select out
so that it doesn't try to match it. And then we can move on and do what we want with it.
Populate
Check advancedResult() methods has 'populate' parameter.
router
.route('/')
.get(advancedResults(Course, 'reviews'), getCourses)
'express' 카테고리의 다른 글
Permission check on user's actions [Express, Node] (0) | 2020.05.21 |
---|---|
When we forgot password/ using registered email. [Express, Node] (0) | 2020.05.21 |
So what do I do with Token? (0) | 2020.05.19 |
TOKEN authentication (0) | 2020.05.19 |
What should I do with Errors? express.js (0) | 2020.05.17 |