Search & Categories
Full-Text Search
Product search uses a denormalized product_search table that caches product data, facet values, and pricing for fast queries.
How It Works
- Products are indexed into
product_searchon create/update - The search table stores a PostgreSQL
tsvectorfor full-text matching - Facet values are stored as JSONB arrays for filtering
minPrice/maxPriceare precomputed from variants
Search API
// Full-text search with facet filters
const results = await productSearchService.searchProducts({
query: "cotton shirt",
facets: { color: ["red", "blue"], size: ["M"] },
page: 1,
limit: 24
});
// Get facet counts for current filters
const counts = await productSearchService.getFilteredFacetCounts(filters);
// Get all product cards (storefront cache)
const allProducts = await productSearchService.getAllProductCards(customerGroupId);Reindexing
// Reindex a single product
await productSearchService.reindexProduct(productId);
// Reindex everything
await productSearchService.reindexAll();Categories
Categories form a hierarchical tree using a parentId self-reference. Each category has a position for ordering and supports multi-language names via translations.
Tree Structure
Electronics (root)
├── Phones
│ ├── Smartphones
│ └── Accessories
└── LaptopsKey Operations
// Get full category tree
const tree = await categoryService.getTree();
// Get breadcrumbs for navigation
const breadcrumbs = await categoryService.getBreadcrumbs(categoryId);
// → [{ id: 1, name: "Electronics" }, { id: 3, name: "Phones" }]
// Get all products in a category (including descendants)
const productIds = await categoryService.getAllProductIds(categoryId);Tax Codes
Categories can carry a taxCode field. When calculating tax for a product, the system checks its first category for the applicable tax rate.
Last updated on