Unlocking the Power of QueryBuilder:
//=> src/app/modules/student/student.service.ts
const getAllDataFromDB = async (query: Record<string, any>) => {
const studentQuery = new QueryBuilder(
Student.find()
.populate('admissionSemester')
.populate({
path: 'academicDepartment',
populate: {
path: 'academicFaculty',
},
}),
query,
)
.search(studentSearchableFields)
.filter()
.sort()
.paginate()
.fields();
const result = await studentQuery.modelQuery;
return result;
}
//==>src/app/builder/QueryBuilder.ts
import { FilterQuery, Query } from 'mongoose';
class QueryBuilder<T> {
public modelQuery: Query<T[], T>;
public query: Record<string, unknown>;
constructor(modelQuery: Query<T[], T>, query: Record<string, unknown>) {
this.modelQuery = modelQuery;
this.query = query;
}
search(searchableFields: string[]) {
const searchTerm = this?.query?.searchTerm;
if (searchTerm) {
this.modelQuery = this.modelQuery.find({
$or: searchableFields.map(
(field) =>
({
[field]: { $regex: searchTerm, $options: 'i' },
}) as FilterQuery<T>,
),
});
}
return this;
}
filter() {
const queryObj = { ...this.query }; // copy
// Filtering
const excludeFields = ['searchTerm', 'sort', 'limit', 'page', 'fields'];
excludeFields.forEach((el) => delete queryObj[el]);
this.modelQuery = this.modelQuery.find(queryObj as FilterQuery<T>);
return this;
}
sort() {
const sort =
(this?.query?.sort as string)?.split(',')?.join(' ') || '-createdAt';
this.modelQuery = this.modelQuery.sort(sort as string);
return this;
}
paginate() {
const page = Number(this?.query?.page) || 1;
const limit = Number(this?.query?.limit) || 10;
const skip = (page - 1) * limit;
this.modelQuery = this.modelQuery.skip(skip).limit(limit);
return this;
}
fields() {
const fields =
(this?.query?.fields as string)?.split(',')?.join(' ') || '-__v';
this.modelQuery = this.modelQuery.select(fields);
return this;
}
}
export default QueryBuilder;
Top comments (0)