[feat] boost card retrieval speed by removing typesense join

This commit is contained in:
2026-05-27 17:32:21 -04:00
parent 6517044821
commit 47f18348bf

View File

@@ -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<string, any[]> = {};
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) => {