feat: Implement dynamic filtering for agent search based on profile fields.

This commit is contained in:
pradeepkumar
2026-02-01 18:30:14 +05:30
parent b8b26b236d
commit bc830a0208
2 changed files with 85 additions and 0 deletions

View File

@@ -141,6 +141,7 @@ export class AgentsService {
limit = 10, limit = 10,
sortBy = 'createdAt', sortBy = 'createdAt',
sortOrder = 'desc', sortOrder = 'desc',
filters,
} = dto; } = dto;
const skip = (page - 1) * limit; const skip = (page - 1) * limit;
@@ -179,6 +180,82 @@ export class AgentsService {
where.agentTypeId = agentTypeId; where.agentTypeId = agentTypeId;
} }
// Process dynamic profile field filters
if (filters) {
try {
const parsedFilters: Record<string, string[]> = JSON.parse(filters);
const filterSlugs = Object.keys(parsedFilters);
if (filterSlugs.length > 0) {
// Get field IDs for the filter slugs
const fields = await this.prisma.profileField.findMany({
where: { slug: { in: filterSlugs } },
select: { id: true, slug: true },
});
const slugToFieldId = new Map(fields.map((f) => [f.slug, f.id]));
// For each filter, find agents that have ANY of the selected values
// Use AND logic between different fields
const filterConditions: string[][] = [];
for (const [slug, selectedValues] of Object.entries(parsedFilters)) {
const fieldId = slugToFieldId.get(slug);
if (!fieldId || !selectedValues || selectedValues.length === 0) continue;
// Find agentProfileIds where jsonValue contains ANY of the selected values
const matchingValues = await this.prisma.agentProfileFieldValue.findMany({
where: {
fieldId,
// jsonValue contains any of the selected values (for MULTI_SELECT, CHECKBOX_GROUP)
// We need to check if the jsonValue array contains any of the selected values
},
select: {
agentProfileId: true,
jsonValue: true,
},
});
// Filter in memory - check if jsonValue array contains any selected value
const matchingAgentIds = matchingValues
.filter((fv) => {
const jsonVal = fv.jsonValue as string[] | null;
if (!jsonVal || !Array.isArray(jsonVal)) return false;
return selectedValues.some((sv) => jsonVal.includes(sv));
})
.map((fv) => fv.agentProfileId);
filterConditions.push(matchingAgentIds);
}
// AND all filter conditions - find intersection of all matching agent IDs
if (filterConditions.length > 0) {
const intersection = filterConditions.reduce((acc, curr) => {
const currSet = new Set(curr);
return acc.filter((id) => currSet.has(id));
});
// If no agents match all filters, return empty result
if (intersection.length === 0) {
return {
data: [],
meta: {
total: 0,
page,
limit,
totalPages: 0,
},
};
}
where.id = { in: intersection };
}
}
} catch {
// Invalid JSON, ignore filters
}
}
// Build orderBy // Build orderBy
const orderBy: Prisma.AgentProfileOrderByWithRelationInput = {}; const orderBy: Prisma.AgentProfileOrderByWithRelationInput = {};
if (sortBy === 'averageRating') { if (sortBy === 'averageRating') {

View File

@@ -72,4 +72,12 @@ export class SearchAgentsDto {
@IsOptional() @IsOptional()
@IsString() @IsString()
sortOrder?: 'asc' | 'desc' = 'desc'; sortOrder?: 'asc' | 'desc' = 'desc';
@ApiPropertyOptional({
description: 'Dynamic profile field filters as JSON string (fieldSlug: [selectedValues])',
example: '{"client_specialization":["first_time_buyers","investors"]}',
})
@IsOptional()
@IsString()
filters?: string;
} }