From 3a1d443a1fd9354562519c3ea88878b172eb9151 Mon Sep 17 00:00:00 2001 From: Thad Miller Date: Fri, 27 Feb 2026 15:27:10 -0500 Subject: [PATCH] [feat] independent facets --- src/pages/partials/cards.astro | 82 ++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 18 deletions(-) diff --git a/src/pages/partials/cards.astro b/src/pages/partials/cards.astro index 87d6dfd..01da188 100644 --- a/src/pages/partials/cards.astro +++ b/src/pages/partials/cards.astro @@ -5,6 +5,17 @@ import RarityIcon from '../../components/RarityIcon.astro'; export const prerender = false; +// all the facet fields we want to use for filtering +const facetFields = { + "productLineName": "Product Line", + "setName": "Set", + "variant": "Variant", + "rarityName": "Rarity", + "cardType": "Card Type", + "energyType": "Energy Type" +} + + // get the query from post request using form data const formData = await Astro.request.formData(); const query = formData.get('q')?.toString() || ''; @@ -27,19 +38,53 @@ const filterBy = Object.entries(filters).map(([field, values]) => { return `${field}:=[${values.join(',')}]`; }).join(' && '); -// use typesense to search for cards matching the query and return the productIds of the results -const searchResults = await client.collections('cards').documents().search({ - q: query, +const facetFilter = (facet:string) => { + const otherFilters = Object.entries(filters) + .filter(([field]) => field !== facet) + .map(([field, values]) => `${field}:=[${values.join(',')}]`) + .join(' && '); + return `sealed:false${otherFilters ? ` && ${otherFilters}` : ''}`; +}; + + +// primary search values (for cards) +let searchArray = [{ + collection: 'cards', filter_by: `sealed:false${filterBy ? ` && ${filterBy}` : ''}`, - query_by: 'productLineName,productName,setName,number,rarityName,Artist', per_page: 20, - facet_by: 'productLineName,setName,variant,rarityName,cardType,energyType', + facet_by: Object.keys(facetFields).join(','), page: Math.floor(start / 20) + 1, sort_by: '_text_match:asc, releaseDate:desc, productName:asc', -}); -const cardIds = searchResults.hits?.map((hit: any) => hit.document.cardId) ?? []; -const totalHits = searchResults.found; -const facets = searchResults.facet_counts; +}]; + +// on first load (start === 0) we want to get the facets for the filters +if (start === 0) { + for (const facet of Object.keys(facetFields)) { + searchArray.push({ + collection: 'cards', + filter_by: facetFilter(facet), + per_page: 0, + facet_by: facet, + page: 1, + sort_by: '' + }); + } +} + +const searchRequests = { searches: searchArray }; +const commonSearchParams = { + q: query, + query_by: 'productLineName,productName,setName,number,rarityName,Artist', +}; + +// use typesense to search for cards matching the query and return the productIds of the results +const searchResults = await client.multiSearch.perform(searchRequests, commonSearchParams); +//console.log(searchResults); +const cardResults = searchResults.results[0] as any; + +const cardIds = cardResults.hits?.map((hit: any) => hit.document.cardId) ?? []; +const totalHits = cardResults?.found; +//const facets = cardResults?.facet_counts; // get pokemon data with prices and set info using searchResults and then query the database for each card to get the prices and set info const pokemon = await db.query.cards.findMany({ @@ -72,14 +117,14 @@ const conditionShort = (condition:string) => { } const facetNames = (name:string) => { - return { - "productLineName": "Product Line", - "setName": "Set", - "variant": "Variant", - "rarityName": "Rarity", - "cardType": "Card Type", - "energyType": "Energy Type" - }[name] || name; + return facetFields[name] || name; +} + +if (start === 0) { + var facets = searchResults.results.slice(1).map((result: any) => { + return result.facet_counts[0]; + }); + console.log(facets); } --- @@ -89,13 +134,13 @@ const facetNames = (name:string) => {
+ {facets.map((facet) => (
{facetNames(facet.field_name)}
{facet.counts.map((count) => (
@@ -103,6 +148,7 @@ const facetNames = (name:string) => { ))}
))} +
}