@@ -129,40 +129,52 @@ class CountryQueryService {
129129
130130 // --- Stage 2: Handle `hasActiveSources` filter ---
131131 if (filter['hasActiveSources' ] == true ) {
132+ // This lookup uses a sub-pipeline to filter for active sources *before*
133+ // joining, which is more efficient than a post-join match.
132134 pipeline.add ({
133135 r'$lookup' : {
134136 'from' : 'sources' ,
135- 'localField' : '_id' ,
136- 'foreignField' : 'headquarters._id' ,
137+ 'let' : {'countryId' : r'$_id' },
138+ 'pipeline' : [
139+ {
140+ r'$match' : {
141+ r'$expr' : {r'$eq' : [r'$headquarters._id' , r'$$countryId' ]},
142+ 'status' : ContentStatus .active.name,
143+ }
144+ }
145+ ],
137146 'as' : 'matchingSources' ,
138147 },
139148 });
140149 pipeline.add ({
141150 r'$match' : {
142- 'matchingSources' : {
143- r'$ne' : < dynamic > [],
144- }, // Ensure there's at least one source
145- 'matchingSources.status' : ContentStatus .active.name,
151+ 'matchingSources' : {r'$ne' : < dynamic > []},
146152 },
147153 });
148154 }
149155
150156 // --- Stage 3: Handle `hasActiveHeadlines` filter ---
151157 if (filter['hasActiveHeadlines' ] == true ) {
158+ // This lookup uses a sub-pipeline to filter for active headlines *before*
159+ // joining, which is more efficient than a post-join match.
152160 pipeline.add ({
153161 r'$lookup' : {
154162 'from' : 'headlines' ,
155- 'localField' : '_id' ,
156- 'foreignField' : 'eventCountry._id' ,
163+ 'let' : {'countryId' : r'$_id' },
164+ 'pipeline' : [
165+ {
166+ r'$match' : {
167+ r'$expr' : {r'$eq' : [r'$eventCountry._id' , r'$$countryId' ]},
168+ 'status' : ContentStatus .active.name,
169+ }
170+ }
171+ ],
157172 'as' : 'matchingHeadlines' ,
158173 },
159174 });
160175 pipeline.add ({
161176 r'$match' : {
162- 'matchingHeadlines' : {
163- r'$ne' : < dynamic > [],
164- }, // Ensure there's at least one headline
165- 'matchingHeadlines.status' : ContentStatus .active.name,
177+ 'matchingHeadlines' : {r'$ne' : < dynamic > []},
166178 },
167179 });
168180 }
@@ -250,7 +262,20 @@ class CountryQueryService {
250262 return pipeline;
251263 }
252264
253- /// Generates a unique cache key from the query parameters.
265+ /// Generates a unique, canonical cache key from the query parameters.
266+ ///
267+ /// A canonical key is essential for effective caching. If two different
268+ /// sets of parameters represent the same logical query (e.g., filters in a
269+ /// different order), they must produce the exact same cache key.
270+ ///
271+ /// This implementation achieves this by:
272+ /// 1. Using a [SplayTreeMap] for the `filter` map, which automatically
273+ /// sorts the filters by their keys.
274+ /// 2. Sorting the `sort` options by their field names.
275+ /// 3. Combining these sorted structures with pagination details into a
276+ /// standard map.
277+ /// 4. Encoding the final map into a JSON string, which serves as the
278+ /// reliable and unique cache key.
254279 String _generateCacheKey (
255280 Map <String , dynamic > filter,
256281 PaginationOptions ? pagination,
0 commit comments