From 47f18348bfefd69b94e47942d73613b245ebf752 Mon Sep 17 00:00:00 2001 From: Thad Miller Date: Wed, 27 May 2026 17:32:21 -0400 Subject: [PATCH] [feat] boost card retrieval speed by removing typesense join --- src/pages/partials/cards.astro | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/pages/partials/cards.astro b/src/pages/partials/cards.astro index cff1cae..efd104e 100644 --- a/src/pages/partials/cards.astro +++ b/src/pages/partials/cards.astro @@ -129,15 +129,15 @@ const facetFilter = (facet:string) => { // primary search values (for cards) -let searchArray = [{ +// Note: no `$skus(...)` join here — see the sku fetch below for why. +let searchArray: any[] = [{ collection: 'cards', - filter_by: `$skus(id:*) && sealed:false${languageFilter}${queryFilter ? ` && ${queryFilter}` : ''}${filterBy ? ` && ${filterBy}` : ''}`, + filter_by: `sealed:false${languageFilter}${queryFilter ? ` && ${queryFilter}` : ''}${filterBy ? ` && ${filterBy}` : ''}`, per_page: 20, facet_by: '', max_facet_values: 0, page: Math.floor(start / 20) + 1, sort_by: resolvedSort, - include_fields: '$skus(*)', }]; // on first load (start === 0) we want to get the facets for the filters @@ -172,6 +172,28 @@ const cardResults = searchResults.results[0] as any; const pokemon = cardResults.hits?.map((hit: any) => hit.document) ?? []; const totalHits = cardResults?.found; +// Skus aren't used for searching or sorting — they only supply the per-condition +// prices displayed on each card. Joining them into the primary search via +// `$skus(id:*)` forces Typesense to materialize the reverse join across the whole +// filtered result set before pagination (~20x slower). Instead, fetch skus for +// just the visible cards in one direct, indexed filter and attach them by id. +if (pokemon.length > 0) { + const cardIds = pokemon.map((c: any) => c.id); + const skuSearch = await client.collections('skus').documents().search({ + q: '*', + query_by: 'condition', + filter_by: `card_id:=[${cardIds.map((id: string) => '`' + id + '`').join(',')}]`, + per_page: 250, + include_fields: 'condition,marketPrice,card_id', + }); + const skusByCard: Record = {}; + for (const hit of (skuSearch.hits ?? []) as any[]) { + const sku = hit.document; + (skusByCard[sku.card_id] ??= []).push(sku); + } + for (const card of pokemon) card.skus = skusByCard[card.id] ?? []; +} + // format price to 2 decimal places (or 0 if price >=100) and adds a $ sign, if the price is null it returns "–" const formatPrice = (condition:string, skus: any) => {