Skip to content

Commit 8f2cc56

Browse files
Merge pull request #1932 from OneCommunityGlobal/Neeraj_Fix_Multi_Category_Filter_Backend
Neeraj Fix Multi Category Filtering
2 parents 94ba54d + 0a1c3b1 commit 8f2cc56

1 file changed

Lines changed: 75 additions & 100 deletions

File tree

src/controllers/jobsController.js

Lines changed: 75 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,167 +1,168 @@
1-
const Job = require('../models/jobs'); // Import the Job model
1+
const Job = require('../models/jobs');
22
const JobPositionCategory = require('../models/jobPositionCategory');
3-
// Controller to fetch all jobs with pagination, search, and filtering
3+
4+
/* ============================================================
5+
INTERNAL: MAIN PAGINATION + FILTERING LOGIC
6+
============================================================ */
47
const paginationForJobs = async (req, res) => {
58
const { page = 1, limit = 18, search = '', category = '', position = '' } = req.query;
69

710
try {
8-
// Validate query parameters
9-
const pageNumber = Math.max(1, parseInt(page, 10)); // Ensure page is at least 1
10-
const limitNumber = Math.max(1, parseInt(limit, 10)); // Ensure limit is at least 1
11+
const pageNumber = Math.max(1, parseInt(page, 10));
12+
const limitNumber = Math.max(1, parseInt(limit, 10));
1113

12-
// Build query conditions
1314
const conditions = [];
14-
const [allCategories, allPositions] = await Promise.all([
15-
JobPositionCategory.distinct('category'),
16-
JobPositionCategory.distinct('position'),
17-
]);
1815

19-
if (search) {
20-
const searchString = String(search);
16+
/* ----------------------------
17+
SEARCH FILTER
18+
---------------------------- */
19+
if (search && search.trim() !== '') {
20+
const searchString = search.trim();
2121
conditions.push({
2222
$or: [
2323
{ title: { $regex: new RegExp(searchString, 'i') } },
2424
{ description: { $regex: new RegExp(searchString, 'i') } },
2525
],
2626
});
27-
} // Case-insensitive search
28-
29-
if (position) conditions.push({ title: { $in: [position] } });
27+
}
3028

31-
if (category) conditions.push({ category: { $in: [category] } });
29+
/* ----------------------------
30+
POSITION FILTER (only if non-empty)
31+
---------------------------- */
32+
if (position && position.trim() !== '') {
33+
conditions.push({ title: { $in: [position.trim()] } });
34+
}
3235

33-
if (allCategories.length) conditions.push({ category: { $in: allCategories } });
34-
if (allPositions.length) conditions.push({ title: { $in: allPositions } });
35-
// Final query
36+
/* ----------------------------
37+
MULTI-CATEGORY FILTER (only if non-empty)
38+
---------------------------- */
39+
if (category && category.trim() !== '') {
40+
const categoryList = category.split(',').map((c) => c.trim());
41+
conditions.push({ category: { $in: categoryList } });
42+
}
3643

3744
const query = conditions.length ? { $and: conditions } : {};
45+
3846
const totalJobs = await Job.countDocuments(query);
47+
const totalPages = Math.ceil(totalJobs / limitNumber);
3948

40-
const totalPages = Math.ceil(totalJobs / limitNumber); // was 20
49+
const pageNum = pageNumber > totalPages ? 1 : pageNumber;
4150

42-
let pageNum;
43-
if (pageNumber > totalPages) pageNum = 1;
44-
else pageNum = pageNumber;
45-
// Fetch paginated results
4651
const jobs = await Job.find(query)
4752
.skip((pageNum - 1) * limitNumber)
4853
.limit(limitNumber);
4954

50-
// Prepare response
5155
res.json({
5256
jobs,
5357
pagination: {
5458
totalJobs,
55-
totalPages: Math.ceil(totalJobs / limitNumber),
56-
currentPage: pageNumber,
59+
totalPages,
60+
currentPage: pageNum,
5761
limit: limitNumber,
58-
hasNextPage: pageNumber < Math.ceil(totalJobs / limitNumber),
59-
hasPreviousPage: pageNumber > 1,
62+
hasNextPage: pageNum < totalPages,
63+
hasPreviousPage: pageNum > 1,
6064
},
6165
});
6266
} catch (error) {
63-
res.status(500).json({ error: 'Failed to fetch Jobs/Summaries', details: error.message });
67+
res.status(500).json({
68+
error: 'Failed to fetch Jobs',
69+
details: error.message,
70+
});
6471
}
6572
};
6673

67-
// Controller to fetch all jobs with pagination, search, and filtering
68-
const getJobs = (req, res) => paginationForJobs(req, res, false);
74+
/* ============================================================
75+
EXPORT: GET JOBS WITH PAGINATION
76+
============================================================ */
77+
const getJobs = (req, res) => paginationForJobs(req, res);
6978

70-
// Controller to fetch job summaries with pagination, search, filtering, and sorting
79+
/* ============================================================
80+
JOB SUMMARIES
81+
============================================================ */
7182
const getJobSummaries = async (req, res) => {
7283
const { search = '', category = '', position = '' } = req.query;
7384

7485
try {
75-
// Build query conditions
7686
const conditions = [];
77-
const [allCategories, allPositions] = await Promise.all([
78-
JobPositionCategory.distinct('category'),
79-
JobPositionCategory.distinct('position'),
80-
]);
8187

82-
if (search) {
83-
const searchString = String(search);
88+
if (search && search.trim() !== '') {
89+
const searchString = search.trim();
8490
conditions.push({
8591
$or: [
8692
{ title: { $regex: new RegExp(searchString, 'i') } },
8793
{ description: { $regex: new RegExp(searchString, 'i') } },
8894
],
8995
});
90-
} // Case-insensitive search
91-
92-
if (position) conditions.push({ title: { $in: [position] } });
96+
}
9397

94-
if (category) conditions.push({ category: { $in: [category] } });
98+
if (position && position.trim() !== '') {
99+
conditions.push({ title: { $in: [position.trim()] } });
100+
}
95101

96-
if (allCategories.length) conditions.push({ category: { $in: allCategories } });
97-
if (allPositions.length) conditions.push({ title: { $in: allPositions } });
98-
// Final query
102+
if (category && category.trim() !== '') {
103+
const categoryList = category.split(',').map((c) => c.trim());
104+
conditions.push({ category: { $in: categoryList } });
105+
}
99106

100107
const query = conditions.length ? { $and: conditions } : {};
101108

102-
// Sorting logic
103109
const sortCriteria = {
104110
displayOrder: 1,
105111
featured: -1,
106112
datePosted: -1,
107113
title: 1,
108114
};
109115

110-
// Fetch the total number of jobs matching the query for pagination
111116
const totalJobs = await Job.countDocuments(query);
112117
const jobs = await Job.find(query)
113118
.select('title category location description datePosted featured jobDetailsLink')
114119
.sort(sortCriteria);
115120

116-
res.json({
117-
jobs,
118-
totalJobs,
119-
});
121+
res.json({ jobs, totalJobs });
120122
} catch (error) {
121-
res.status(500).json({ error: 'Failed to fetch job summaries', details: error.message });
123+
res.status(500).json({
124+
error: 'Failed to fetch job summaries',
125+
details: error.message,
126+
});
122127
}
123128
};
124129

125-
// Controller to fetch job title suggestions for a dropdown
130+
/* ============================================================
131+
OTHER CONTROLLERS
132+
============================================================ */
126133
const getJobTitleSuggestions = async (req, res) => {
127134
const { query = '' } = req.query;
128-
129135
try {
130-
const suggestions = await Job.find({ title: { $regex: query, $options: 'i' } }).distinct(
131-
'title',
132-
);
136+
const suggestions = await Job.find({
137+
title: { $regex: query, $options: 'i' },
138+
}).distinct('title');
133139

134140
res.json({ suggestions });
135141
} catch (error) {
136-
res
137-
.status(500)
138-
.json({ error: 'Failed to fetch job title suggestions', details: error.message });
142+
res.status(500).json({ error: 'Failed to fetch job title suggestions' });
139143
}
140144
};
141145

142146
const resetJobsFilters = async (req, res) => {
143147
const { page = 1, limit = 18 } = req.query;
144148

145149
try {
146-
// Validate pagination parameters
147150
const pageNumber = Math.max(1, parseInt(page, 10));
148151
const limitNumber = Math.max(1, parseInt(limit, 10));
149152

150-
// Sorting logic
151153
const sortCriteria = {
152154
displayOrder: 1,
153155
featured: -1,
154156
datePosted: -1,
155157
title: 1,
156158
};
157-
// Fetch all jobs without filtering
159+
158160
const totalJobs = await Job.countDocuments({});
159161
const jobs = await Job.find({})
160162
.sort(sortCriteria)
161163
.skip((pageNumber - 1) * limitNumber)
162164
.limit(limitNumber);
163165

164-
// Respond with all jobs and pagination metadata
165166
res.json({
166167
jobs,
167168
pagination: {
@@ -174,64 +175,50 @@ const resetJobsFilters = async (req, res) => {
174175
},
175176
});
176177
} catch (error) {
177-
res
178-
.status(500)
179-
.json({ error: 'Failed to reset filters or reload jobs', details: error.message });
178+
res.status(500).json({ error: 'Failed to reset filters', details: error.message });
180179
}
181180
};
182181

183182
const getCategories = async (req, res) => {
184183
try {
185-
// const categories = await Job.distinct('category', {});
186184
const categories = await JobPositionCategory.distinct('category', {});
187-
// Sort categories alphabetically
188185
categories.sort((a, b) => a.localeCompare(b));
189-
190186
res.status(200).json({ categories });
191-
} catch (error) {
187+
} catch {
192188
res.status(500).json({ message: 'Failed to fetch categories' });
193189
}
194190
};
191+
195192
const getPositions = async (req, res) => {
196193
try {
197194
const positions = await JobPositionCategory.distinct('position', {});
198-
199-
// Sort categories alphabetically
200195
positions.sort((a, b) => a.localeCompare(b));
201-
202196
res.status(200).json({ positions });
203-
} catch (error) {
197+
} catch {
204198
res.status(500).json({ message: 'Failed to fetch positions' });
205199
}
206200
};
207201

208-
// Controller to fetch job details by ID
209202
const getJobById = async (req, res) => {
210203
const { id } = req.params;
211-
212204
try {
213205
const job = await Job.findById(id);
214-
if (!job) {
215-
return res.status(404).json({ error: 'Job not found' });
216-
}
206+
if (!job) return res.status(404).json({ error: 'Job not found' });
217207
res.json(job);
218208
} catch (error) {
219209
res.status(500).json({ error: 'Failed to fetch job', details: error.message });
220210
}
221211
};
222212

223-
// Controller to create a new job
224213
const createJob = async (req, res) => {
225214
const { title, category, description, imageUrl, location, applyLink, jobDetailsLink } = req.body;
226215

227216
try {
228-
// Find the highest displayOrder value currently in use
229217
const highestOrderJob = await Job.findOne().sort({ displayOrder: -1 }).limit(1);
230218
const newDisplayOrder = highestOrderJob ? highestOrderJob.displayOrder + 1 : 0;
231219

232220
const newJob = new Job({
233221
title,
234-
// summaries,
235222
category,
236223
description,
237224
imageUrl,
@@ -248,47 +235,37 @@ const createJob = async (req, res) => {
248235
}
249236
};
250237

251-
// Controller to update an existing job by ID
252238
const updateJob = async (req, res) => {
253239
const { id } = req.params;
254240

255241
try {
256242
const updatedJob = await Job.findByIdAndUpdate(id, req.body, { new: true });
257-
if (!updatedJob) {
258-
return res.status(404).json({ error: 'Job not found' });
259-
}
243+
if (!updatedJob) return res.status(404).json({ error: 'Job not found' });
260244
res.json(updatedJob);
261245
} catch (error) {
262246
res.status(500).json({ error: 'Failed to update job', details: error.message });
263247
}
264248
};
265249

266-
// Controller to delete a job by ID
267250
const deleteJob = async (req, res) => {
268251
const { id } = req.params;
269252

270253
try {
271254
const deletedJob = await Job.findByIdAndDelete(id);
272-
if (!deletedJob) {
273-
return res.status(404).json({ error: 'Job not found' });
274-
}
255+
if (!deletedJob) return res.status(404).json({ error: 'Job not found' });
275256
res.json({ message: 'Job deleted successfully' });
276257
} catch (error) {
277258
res.status(500).json({ error: 'Failed to delete job', details: error.message });
278259
}
279260
};
280261

281-
// Controller to reorder jobs
282262
const reorderJobs = async (req, res) => {
283263
const { jobIds } = req.body;
284264

285265
try {
286-
// Validate input
287-
if (!Array.isArray(jobIds) || jobIds.length === 0) {
266+
if (!Array.isArray(jobIds) || jobIds.length === 0)
288267
return res.status(400).json({ error: 'Invalid job order data' });
289-
}
290268

291-
// Update the order of each job
292269
const updateOperations = jobIds.map((jobId, index) => ({
293270
updateOne: {
294271
filter: { _id: jobId },
@@ -298,7 +275,6 @@ const reorderJobs = async (req, res) => {
298275

299276
await Job.bulkWrite(updateOperations);
300277

301-
// Fetch and return the updated jobs
302278
const jobs = await Job.find({ _id: { $in: jobIds } }).sort({ displayOrder: 1 });
303279

304280
res.json({
@@ -311,7 +287,6 @@ const reorderJobs = async (req, res) => {
311287
}
312288
};
313289

314-
// Export controllers as a plain object
315290
module.exports = {
316291
getJobs,
317292
getJobTitleSuggestions,

0 commit comments

Comments
 (0)