Understanding Advanced Search Requirements
Imagine you're a school administrator trying to find classrooms that match specific criteria. You might need to find all classrooms with "Mr." in the name, or all classrooms that can accommodate between 25-30 students. These are the kinds of flexible search capabilities we'll implement in this phase.
Key Search Features
We'll implement two main types of searches:
1. Pattern matching for classroom names (like finding all "Mr." classrooms)
2. Numeric range searches for student limits (like finding rooms that fit 20-30 students)
Implementing Name Pattern Matching
Let's start with implementing the classroom name search. This is similar to how you might search for a contact in your phone - partial matches should work.
Name Search Implementation
const { Op } = require('sequelize');
const getClassrooms = async (req, res) => {
try {
const { name } = req.query;
const whereClause = {};
// Add name filter if provided
if (name) {
whereClause.name = {
[Op.like]: `%${name}%`
};
}
const classrooms = await Classroom.findAll({
where: whereClause,
order: [['name', 'ASC']]
});
res.json(classrooms);
} catch (error) {
console.error('Error in classroom search:', error);
res.status(500).json({
error: 'Failed to search classrooms'
});
}
};
The '%' wildcards in SQL LIKE queries work similarly to how we might search a phonebook:
- '%mr%' would match "Mr. Smith", "Mrs. Jones", "Mr. Anderson"
- 'mr.%' would only match "Mr. Smith", "Mr. Anderson"
- '%room%' would match "Classroom 101", "Room A", "Homeroom"
Implementing Student Limit Range Search
Now let's implement the ability to search for classrooms based on their student capacity. This is more complex because we need to handle both exact matches and ranges.
Student Limit Search Implementation
const handleStudentLimitFilter = (studentLimit) => {
if (!studentLimit) return null;
// Check if it's a range query (contains comma)
if (studentLimit.includes(',')) {
const [min, max] = studentLimit.split(',').map(Number);
// Validate the range values
if (isNaN(min) || isNaN(max)) {
throw new Error('Student Limit should be two numbers: min,max');
}
if (min > max) {
throw new Error('Minimum limit cannot be greater than maximum limit');
}
return {
[Op.between]: [min, max]
};
}
// Handle exact match
const limit = Number(studentLimit);
if (isNaN(limit)) {
throw new Error('Student Limit should be an integer');
}
return limit;
};
const getClassroomsWithFilters = async (req, res) => {
try {
const { name, studentLimit } = req.query;
const whereClause = {};
// Add name filter if provided
if (name) {
whereClause.name = {
[Op.like]: `%${name}%`
};
}
// Add student limit filter if provided
if (studentLimit) {
try {
const limitFilter = handleStudentLimitFilter(studentLimit);
if (limitFilter) {
whereClause.studentLimit = limitFilter;
}
} catch (error) {
return res.status(400).json({
errors: [{ message: error.message }],
count: 0,
pageCount: 0
});
}
}
const classrooms = await Classroom.findAll({
where: whereClause,
order: [['name', 'ASC']]
});
res.json(classrooms);
} catch (error) {
console.error('Error in classroom search:', error);
res.status(500).json({
error: 'Failed to search classrooms'
});
}
};
Handling Complex Search Scenarios
Let's look at how our implementation handles different search scenarios:
Scenario 1: Simple Name Search
GET /classrooms?name=mr
This will find all classrooms with "mr" in their name, case-insensitive.
Scenario 2: Exact Student Limit
GET /classrooms?studentLimit=25
This will find classrooms that can hold exactly 25 students.
Scenario 3: Student Limit Range
GET /classrooms?studentLimit=20,30
This will find classrooms that can hold between 20 and 30 students.
Scenario 4: Combined Search
GET /classrooms?name=mr&studentLimit=20,30
This will find classrooms with "mr" in the name that can hold between 20 and 30 students.
Error Handling and Edge Cases
Proper error handling is crucial for a robust search system. Let's look at how we handle various edge cases:
Comprehensive Error Handling
const validateSearchParams = (params) => {
const errors = [];
if (params.studentLimit) {
if (params.studentLimit.includes(',')) {
const [min, max] = params.studentLimit.split(',').map(Number);
if (isNaN(min) || isNaN(max)) {
errors.push('Student Limit should be two numbers: min,max');
} else if (min > max) {
errors.push('Minimum limit cannot be greater than maximum limit');
}
} else {
const limit = Number(params.studentLimit);
if (isNaN(limit)) {
errors.push('Student Limit should be an integer');
}
}
}
return errors;
};
Best Practices and Performance Considerations
Optimization Tips
When implementing classroom searches, consider these optimization strategies:
1. Add database indexes on frequently searched columns (name, studentLimit)
2. Use query parameter validation to prevent unnecessary database queries
3. Consider implementing result caching for common searches
4. Use parameterized queries to prevent SQL injection
Practical Applications
This search functionality enables several important administrative tasks:
1. Finding available classrooms for a specific class size
2. Locating all classrooms assigned to a specific teacher
3. Identifying classrooms that might need capacity adjustments
4. Planning classroom assignments for the next semester
Exercise: Extended Search Features
Try implementing these additional search features:
1. Search by floor number or building wing
2. Filter by classrooms that are currently under or over capacity
3. Search by available resources (whiteboard, projector, etc.)