Skills Development Algolia Search with Filtering and Faceting

Algolia Search with Filtering and Faceting

v20260423
algolia-core-workflow-a
This comprehensive workflow guides the implementation of a core Algolia search feature. It covers advanced concepts such as full-text search, combining multiple filters (e.g., price range, stock status), utilizing faceted navigation for refined filtering, managing pagination, and displaying highlighted search results. This is essential for building robust and highly functional e-commerce search UIs.
Get Skill
273 downloads
Overview

Algolia Core Workflow A — Search & Filtering

Overview

Primary Algolia workflow: full-text search with filters, faceted navigation, hit highlighting, and pagination. Uses searchSingleIndex (v5) with real Algolia search parameters.

Prerequisites

  • Completed algolia-install-auth and algolia-hello-world setup
  • Index populated with records (see algolia-hello-world)
  • Index settings configured with searchableAttributes and attributesForFaceting

Instructions

Step 1: Configure Index for Filtering

import { algoliasearch } from 'algoliasearch';

const client = algoliasearch(process.env.ALGOLIA_APP_ID!, process.env.ALGOLIA_ADMIN_KEY!);

await client.setSettings({
  indexName: 'products',
  indexSettings: {
    // What to search (ordered = priority matters)
    searchableAttributes: ['name', 'description', 'brand', 'category'],

    // What to filter/facet on — prefix with filterOnly() if no facet counts needed
    attributesForFaceting: [
      'searchable(brand)',           // Searchable facet: users can search within brand values
      'category',                     // Regular facet: shown in facet panels
      'filterOnly(price)',           // Filter only: no counts computed, saves CPU
      'filterOnly(in_stock)',
    ],

    // Custom ranking: tie-breaker after Algolia's relevance ranking
    customRanking: ['desc(sales_count)', 'desc(rating)'],

    // What comes back in hits
    attributesToRetrieve: ['name', 'brand', 'price', 'image_url', 'category'],
    attributesToHighlight: ['name', 'description'],
    attributesToSnippet: ['description:30'],  // 30-word snippet
  },
});

Step 2: Search with Filters

// Algolia filter syntax uses SQL-like expressions
const { hits, nbHits, facets } = await client.searchSingleIndex({
  indexName: 'products',
  searchParams: {
    query: 'running shoes',

    // Numeric/boolean/string filters
    filters: 'price < 150 AND in_stock = true',

    // OR: facetFilters for UI-driven filtering (array = OR, nested = AND)
    // facetFilters: [['category:shoes', 'category:sneakers'], ['brand:Nike']],
    //   ^ shoes OR sneakers, AND brand is Nike

    // Numeric range filters
    numericFilters: ['price >= 50', 'price <= 150'],

    // Request facet counts for these attributes
    facets: ['category', 'brand'],

    // Pagination
    hitsPerPage: 20,
    page: 0,

    // Highlighting
    highlightPreTag: '<mark>',
    highlightPostTag: '</mark>',
  },
});

console.log(`${nbHits} results found`);

// Access facet counts for building filter UI
// facets = { category: { shoes: 42, sneakers: 18 }, brand: { Nike: 30, Adidas: 25 } }
for (const [facetName, values] of Object.entries(facets || {})) {
  console.log(`${facetName}:`);
  for (const [value, count] of Object.entries(values)) {
    console.log(`  ${value}: ${count}`);
  }
}

Step 3: Display Highlighted Results

hits.forEach(hit => {
  // _highlightResult contains highlighted versions of each field
  const highlighted = hit._highlightResult;
  const name = highlighted?.name?.value || hit.name;
  const snippet = hit._snippetResult?.description?.value || '';

  console.log(`${name} — $${hit.price}`);
  if (snippet) console.log(`  ${snippet}`);
});

Step 4: Implement Pagination

async function paginatedSearch(query: string, page: number = 0) {
  const { hits, nbHits, nbPages, hitsPerPage } = await client.searchSingleIndex({
    indexName: 'products',
    searchParams: {
      query,
      hitsPerPage: 20,
      page,
    },
  });

  return {
    hits,
    totalHits: nbHits,
    totalPages: nbPages,
    currentPage: page,
    hasMore: page < nbPages - 1,
  };
}

Error Handling

ErrorCauseSolution
Invalid filter syntaxMalformed filters stringCheck filter syntax: field:value, field < N, use AND/OR/NOT
Attribute not valid for filteringField not in attributesForFacetingAdd field to attributesForFaceting in settings
0 results unexpectedlyTypo tolerance may be disabledCheck typoTolerance setting; verify data is indexed
Stale results after updateDidn't wait for taskUse await client.waitForTask() after indexing

Examples

Multi-Index Search (Federated)

const { results } = await client.search({
  requests: [
    { indexName: 'products', query: 'laptop', hitsPerPage: 5 },
    { indexName: 'articles', query: 'laptop', hitsPerPage: 3 },
  ],
});

// results[0].hits = product hits, results[1].hits = article hits

Search with Optional Filters (boost, not require)

const { hits } = await client.searchSingleIndex({
  indexName: 'products',
  searchParams: {
    query: 'shoes',
    optionalFilters: ['brand:Nike'],  // Nike products ranked higher but not required
  },
});

Resources

Next Steps

For indexing and data sync workflows, see algolia-core-workflow-b.

Info
Category Development
Name algolia-core-workflow-a
Version v20260423
Size 5.67KB
Updated At 2026-04-26
Language