This document describes the comprehensive search system implemented for PetChain, including full-text search, faceted filtering, autocomplete, analytics, and geolocation capabilities.
- PostgreSQL ILIKE-based text search across multiple fields
- Search across Pets, Vets, Medical Records, and Emergency Services
- Global search capability across all entities simultaneously
- Query optimization with proper indexes
Pet Filters:
- Breed
- Age range (min/max)
- Location
- Status (active, missing, deceased)
Vet Filters:
- Specialty
- Location
- Rating
- Availability status
Medical Record Filters:
- Condition
- Treatment
- Date range
- Status
Emergency Service Filters:
- Service type
- 24/7 availability
- Location
- Rating
- Real-time autocomplete as users type (2+ characters)
- Debounced API calls (300ms) for performance
- Type-specific suggestions based on search domain
- Display of popular searches from analytics
Tracked Metrics:
- Query text
- Search type (pets, vets, etc.)
- Results count
- Response time
- Filter usage
- Success rate
- User information (optional)
Analytics Dashboard:
- Total searches
- Success rate
- Average response time
- Searches by type
- Popular queries with counts
- Browser geolocation integration
- Haversine formula for distance calculation
- Configurable radius (default: 10km for general, 50km for emergency)
- Distance-based sorting for emergency services
- "Use My Location" button with loading state
- Redis container added to docker-compose
- Cache infrastructure ready for implementation
- Designed for sub-50ms response times with cache hits
- Automatic tracking of search execution time
- Response time analytics
- Query performance insights
- Historical performance data
backend/src/modules/
├── pets/
│ ├── entities/pet.entity.ts
│ ├── dto/
│ ├── pets.controller.ts
│ ├── pets.service.ts
│ └── pets.module.ts
├── medical-records/
├── vets/
├── emergency-services/
└── search/
├── entities/search-analytics.entity.ts
├── dto/search-query.dto.ts
├── interfaces/search-result.interface.ts
├── search.controller.ts
├── search.service.ts
└── search.module.ts
src/
├── components/
│ ├── SearchBar.tsx # Main search input with filters
│ └── SearchResults.tsx # Results display with pagination
├── pages/
│ └── search.tsx # Search page with tabs
└── utils/
└── debounce.ts # Utility for debouncing
GET /api/v1/search/pets
GET /api/v1/search/vets
GET /api/v1/search/medical-records
GET /api/v1/search/emergency-services
GET /api/v1/search/global
GET /api/v1/search/autocomplete
GET /api/v1/search/popular
GET /api/v1/search/analytics
{
query?: string;
type?: string;
page?: number;
limit?: number;
// Filters
breed?: string;
minAge?: number;
maxAge?: number;
location?: string;
specialty?: string;
condition?: string;
treatment?: string;
serviceType?: string;
is24Hours?: boolean;
// Geolocation
latitude?: number;
longitude?: number;
radius?: number;
// Sorting
sortBy?: 'relevance' | 'date' | 'distance' | 'rating' | 'name';
sortOrder?: 'ASC' | 'DESC';
}- Pet: name, breed, species, age, location, coordinates, status
- MedicalRecord: condition, treatment, diagnosis, medications, attachments
- Vet: name, specialty, location, coordinates, rating, experience
- EmergencyService: name, serviceType, location, coordinates, 24/7 status
- SearchAnalytics: query, searchType, resultsCount, responseTime, filters
- Full-text search fields (breed, condition, specialty, etc.)
- Location fields for geolocation queries
- Created/updated timestamps
- Foreign keys for relationships
// Search pets by breed and location
const results = await searchService.searchPets({
query: "golden retriever",
location: "San Francisco",
minAge: 1,
maxAge: 5,
page: 1,
limit: 10,
});
// Geolocation search for emergency services
const nearby = await searchService.searchEmergencyServices({
latitude: 37.7749,
longitude: -122.4194,
radius: 25,
is24Hours: true,
sortBy: "distance",
});
// Get autocomplete suggestions
const suggestions = await searchService.autocomplete("golden", "pets");
// Get popular queries
const popular = await searchService.getPopularQueries(10);
// Get analytics
const analytics = await searchService.getSearchAnalytics(7);import SearchBar from "@/components/SearchBar";
import SearchResults from "@/components/SearchResults";
function MySearchPage() {
const handleSearch = async (query, filters) => {
const response = await fetch(`/api/v1/search/pets?query=${query}&...`);
const data = await response.json();
setResults(data);
};
return (
<>
<SearchBar onSearch={handleSearch} searchType="pets" showFilters={true} />
<SearchResults
results={results.results}
total={results.total}
page={results.page}
totalPages={results.totalPages}
onPageChange={handlePageChange}
renderItem={renderPetCard}
/>
</>
);
}- Database Indexes: Strategic indexes on searchable fields
- Query Optimization: Efficient WHERE clauses and JOIN operations
- Pagination: Limit result sets with configurable page sizes
- Debouncing: 300ms debounce on autocomplete to reduce API calls
- Geolocation Caching: User location cached in session
- Redis Ready: Infrastructure for caching frequent queries
cd backend
docker-compose up -d
npm install
npm run start:devnpm install
npm run dev- Open http://localhost:3000/search
- Try different search types (Pets, Vets, etc.)
- Test filters and geolocation
- Check analytics at
/api/v1/search/analytics
- Elasticsearch Integration: For even more powerful full-text search
- Machine Learning: Learn from user behavior to improve relevance
- Voice Search: Add speech-to-text capabilities
- Search History: Per-user search history
- Saved Searches: Allow users to save frequent searches
- Advanced Filters: More granular filtering options
- Export Results: Download search results as CSV/PDF
No results returned:
- Check database has data
- Verify API endpoints are accessible
- Check console for errors
Geolocation not working:
- Ensure HTTPS or localhost
- Check browser permissions
- Verify coordinates in filters
Autocomplete not appearing:
- Check minimum 2 characters typed
- Verify debounce timing
- Check API response in network tab
For issues or questions:
- Check the main README.md
- Open a GitHub issue
- Contact @llins_x