Skip to content

Commit e542d52

Browse files
authored
Merge pull request #256 from map-of-pi/bug/fix-search-filtering
Self approved.
2 parents 5eb57b5 + e504e88 commit e542d52

File tree

3 files changed

+54
-44
lines changed

3 files changed

+54
-44
lines changed

src/controllers/sellerController.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ export const fetchSellersByCriteria = async (req: Request, res: Response) => {
1212
const sellers = await sellerService.getAllSellers(bounds, search_query, userId);
1313

1414
if (!sellers || sellers.length === 0) {
15-
logger.warn(`No sellers found within bounds (${bounds?.sw_lat}, ${bounds?.sw_lng}) to (${bounds?.ne_lat}, ${bounds?.ne_lng}) with "${search_query ?? 'undefined'}"`);
15+
logger.warn(`No sellers found within bounds (${bounds?.sw_lat}, ${bounds?.sw_lng}) to (${bounds?.ne_lat}, ${bounds?.ne_lng}) with ${search_query}`);
1616
return res.status(204).json({ message: "Sellers not found" });
1717
}
18-
logger.info(`Fetched ${sellers.length} sellers within bounds (${bounds?.sw_lat}, ${bounds?.sw_lng}) to (${bounds?.ne_lat}, ${bounds?.ne_lng}) with "${search_query ?? 'undefined'}"`);
18+
logger.info(`Fetched ${sellers.length} sellers within bounds (${bounds?.sw_lat}, ${bounds?.sw_lng}) to (${bounds?.ne_lat}, ${bounds?.ne_lng}) with ${search_query}`);
1919
return res.status(200).json(sellers);
2020
} catch (error) {
2121
logger.error('Failed to fetch sellers by criteria:', error);

src/services/seller.service.ts

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const resolveSellerSettings = async (
4141
if (trustLevelFilters && !trustLevelFilters.includes(trustMeterRating)) {
4242
return null; // Exclude this seller
4343
}
44-
44+
4545
try {
4646
return {
4747
...sellerObject,
@@ -83,15 +83,19 @@ export const getAllSellers = async (
8383

8484
// Construct base filter criteria
8585
const baseCriteria: Record<string, any> = {};
86+
87+
// [Seller Type Filter]
8688
const sellerTypeFilters: SellerType[] = [];
87-
8889
if (searchFilters.include_active_sellers) sellerTypeFilters.push(SellerType.Active);
8990
if (searchFilters.include_inactive_sellers) sellerTypeFilters.push(SellerType.Inactive);
9091
if (searchFilters.include_test_sellers) sellerTypeFilters.push(SellerType.Test);
92+
9193
// include filtered seller types
92-
if (sellerTypeFilters.length) baseCriteria.seller_type = { $in: sellerTypeFilters };
94+
if (sellerTypeFilters.length > 0) {
95+
baseCriteria.seller_type = { $in: sellerTypeFilters };
96+
}
9397

94-
// Trust Level Filters
98+
// [Trust Level Filters]
9599
const trustLevels = [
96100
{ key: "include_trust_level_100", value: TrustMeterScale.HUNDRED },
97101
{ key: "include_trust_level_80", value: TrustMeterScale.EIGHTY },
@@ -102,7 +106,7 @@ export const getAllSellers = async (
102106
.filter(({ key }) => searchFilters[key]) // Only include checked trust levels
103107
.map(({ value }) => value);
104108

105-
// Search Query Filter
109+
// [Search Query Filter]
106110
const searchCriteria = search_query
107111
? {
108112
$text: {
@@ -112,45 +116,40 @@ export const getAllSellers = async (
112116
}
113117
: {}; // default to empty object if search_query not provided
114118

115-
// Merge filters
116-
const aggregatedCriteria = { ...baseCriteria, ...searchCriteria };
117-
118-
let sellers: ISeller[];
119-
// If bounds are provided, use MongoDB's $geometry operator
120-
if (bounds && !search_query) {
121-
sellers = await Seller.find({
122-
...aggregatedCriteria,
123-
sell_map_center: {
124-
$geoWithin: {
125-
$geometry: {
126-
type: "Polygon",
127-
coordinates: [ [
128-
[bounds.sw_lng, bounds.sw_lat],
129-
[bounds.ne_lng, bounds.sw_lat],
130-
[bounds.ne_lng, bounds.ne_lat],
131-
[bounds.sw_lng, bounds.ne_lat],
132-
[bounds.sw_lng, bounds.sw_lat]
133-
] ]
134-
}
135-
}
119+
// [Geo Filter]
120+
const locationCriteria = bounds
121+
? {
122+
sell_map_center: {
123+
$geoWithin: {
124+
$geometry: {
125+
type: "Polygon",
126+
coordinates: [[
127+
[bounds.sw_lng, bounds.sw_lat],
128+
[bounds.ne_lng, bounds.sw_lat],
129+
[bounds.ne_lng, bounds.ne_lat],
130+
[bounds.sw_lng, bounds.ne_lat],
131+
[bounds.sw_lng, bounds.sw_lat],
132+
]],
133+
},
134+
},
135+
},
136136
}
137-
})
138-
.sort({ updatedAt: -1 }) // Sort by last updated
137+
: {};
138+
139+
// [Final Aggregated Criteria]
140+
const aggregatedCriteria = {
141+
...baseCriteria,
142+
...searchCriteria,
143+
...locationCriteria,
144+
};
145+
146+
const sellers = await Seller.find(aggregatedCriteria)
147+
.sort({ updatedAt: -1 })
139148
.limit(maxNumSellers)
140-
.hint({ 'updatedAt': -1, 'sell_map_center.coordinates': '2dsphere' })
141149
.exec();
142-
} else {
143-
// If no bounds are provided, return all sellers (without geo-filtering)
144-
sellers = await Seller.find(aggregatedCriteria)
145-
.sort({ updated_at: -1 })
146-
.limit(maxNumSellers)
147-
.exec();
148-
}
149150

150151
// Fetch and merge the settings for each seller
151152
const sellersWithSettings = await resolveSellerSettings(sellers, trustLevelFilters);
152-
153-
// Return sellers with their settings merged
154153
return sellersWithSettings;
155154
} catch (error) {
156155
logger.error('Failed to get all sellers:', error);

test/services/seller.service.spec.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
getSellersWithinSanctionedRegion
1010
} from '../../src/services/seller.service';
1111
import User from '../../src/models/User';
12-
import { SellerType } from '../../src/models/enums/sellerType';
1312
import { RestrictedArea, RestrictedAreaBoundaries } from '../../src/models/enums/restrictedArea';
1413
import { IUser, ISeller, ISellerItem, ISanctionedRegion } from '../../src/types';
1514

@@ -57,7 +56,6 @@ describe('getAllSellers function', () => {
5756
// filter seller records to include those with sell_map_center within geospatial bounding box
5857
expect(sellersData).toHaveLength(
5958
await Seller.countDocuments({
60-
seller_type: { $ne: SellerType.Inactive },
6159
'sell_map_center.coordinates': {
6260
$geoWithin: {
6361
$box: [
@@ -71,13 +69,26 @@ describe('getAllSellers function', () => {
7169
});
7270

7371
it('should fetch all applicable sellers when all parameters are provided', async () => {
72+
const searchQuery = 'Seller';
7473
const userData = await User.findOne({ pi_username: 'TestUser1' }) as IUser;
7574

76-
const sellersData = await getAllSellers(mockBoundingBox, 'Vendor', userData.pi_uid);
75+
const sellersData = await getAllSellers(mockBoundingBox, searchQuery, userData.pi_uid);
7776

7877
/* filter seller records to include those with "Vendor"
7978
+ include those with sell_map_center within geospatial bounding box */
80-
expect(sellersData).toHaveLength(3);
79+
expect(sellersData).toHaveLength(
80+
await Seller.countDocuments({
81+
$text: { $search: searchQuery, $caseSensitive: false },
82+
'sell_map_center.coordinates': {
83+
$geoWithin: {
84+
$box: [
85+
[mockBoundingBox.sw_lng, mockBoundingBox.sw_lat],
86+
[mockBoundingBox.ne_lng, mockBoundingBox.ne_lat]
87+
]
88+
},
89+
},
90+
})
91+
); // Ensure length matches expected sellers
8192
});
8293
});
8394

0 commit comments

Comments
 (0)