Product Parameter Filtering for E-Commerce

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Showing 1 of 1 servicesAll 2065 services
Product Parameter Filtering for E-Commerce
Medium
~3-5 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    847
  • image_website-sbh_0.png
    Website development for SBH Partners
    999
  • image_website-_0.png
    Website development for Red Pear
    451

Product Filtering Development for E-Commerce

Filtering is one of the main navigation tools in catalog. User with 500 laptops doesn't browse pages — filters by brand, RAM, screen size. Poor filtering loses these sales. Good filtering is faceted search: available filter values update based on selections made, and user always knows how many products match each value.

Filter Types

Type UX Component Example Technical
Multiple selection Checkboxes Brand: Apple, Samsung WHERE brand IN (...)
Single selection Radio buttons Condition: new/used WHERE condition = ...
Numeric range Slider with handles Price: 5000–30000 WHERE price BETWEEN ...
Range via inputs "From" and "To" fields Diagonal: 13–15.6" WHERE diagonal BETWEEN ...
Boolean Toggle In stock only WHERE stock > 0
Rating Stars (≥N) Rating from 4 WHERE rating >= 4
Color Color swatches Color: black, silver WHERE color IN (...)

Faceted Search with SQL

Simplest approach — filtering via PostgreSQL. Works up to ~100,000 products with proper indexing.

-- Main query with filters
SELECT p.* FROM products p
WHERE p.category_id = :cat
  AND (:brands IS NULL OR p.brand = ANY(:brands::text[]))
  AND (:price_min IS NULL OR p.price >= :price_min)
  AND (:price_max IS NULL OR p.price <= :price_max)
  AND (:in_stock IS NULL OR p.stock > 0)
ORDER BY p.sort_order
LIMIT 48 OFFSET :offset;

-- Aggregations for counters (separate query per filter)
SELECT brand, COUNT(*) FROM products p
WHERE p.category_id = :cat
  -- All filters EXCEPT brand
  AND (:price_min IS NULL OR p.price >= :price_min)
GROUP BY brand;

Problem with SQL approach: for correct counters need separate aggregation query for each filter, excluding that filter from conditions. With 10 active filters — 10 additional queries. Doesn't scale on real load.

Faceted Search with Elasticsearch

Elasticsearch solves task in one request via aggregations:

{
  "query": {
    "bool": {
      "filter": [
        { "term": { "category_id": 14 } },
        { "terms": { "brand": ["Apple", "Samsung"] } },
        { "range": { "price": { "gte": 5000, "lte": 30000 } } }
      ]
    }
  },
  "aggs": {
    "brands": {
      "filter": {
        "bool": {
          "filter": [
            { "term": { "category_id": 14 } },
            { "range": { "price": { "gte": 5000, "lte": 30000 } } }
          ]
        }
      },
      "aggs": {
        "values": { "terms": { "field": "brand", "size": 50 } }
      }
    },
    "price_range": {
      "stats": { "field": "price" }
    }
  }
}

Each aggregation (brands, ram, screen_size) uses filter without its own condition — that's faceted search. One request returns both products and counters for all filters.

URL Schema for Filters

URL must reflect filter state for sharing and SEO:

/laptops?brand=apple,samsung&ram=16&price_min=50000&price_max=100000&sort=price_asc

On filter change — pushState or replaceState without page reload. On direct URL entry — initialize filter state from parameters.

SEO approach: popular filter combinations (brand + category) as separate static pages with unique content and canonical. Rare combination pages — <meta name="robots" content="noindex">.

Client Implementation

Filter state stored in URL (source of truth) mirrored in React state:

type FilterState = {
  brands: string[];
  ram: number | null;
  priceMin: number | null;
  priceMax: number | null;
  inStock: boolean;
  sort: 'price_asc' | 'price_desc' | 'popularity' | 'rating';
};

function useFilters() {
  const [searchParams, setSearchParams] = useSearchParams();

  const filters = useMemo(() => parseFilters(searchParams), [searchParams]);

  const setFilter = (key: keyof FilterState, value: unknown) => {
    const next = { ...filters, [key]: value };
    setSearchParams(buildParams(next), { replace: true });
  };

  return { filters, setFilter };
}

On filter change — debounce 300ms, then API request. Results update without page reload.

Price Slider

Price range component — separate task. Requirements:

  • Two handles (min/max) that can't cross
  • Keyboard input validation and clamp
  • Histogram of price distribution behind slider (shows where products concentrate)

Histogram: Elasticsearch histogram aggregation with interval = (max_price - min_price) / 20. Display via SVG path or tiny bar chart.

Ready components: @radix-ui/react-slider, rc-slider, noUiSlider. Radix option preferred with Tailwind stack.

Performance Optimization

Aggregation caching: facet counts don't change per request. Cache aggregation results for category with typical filter set in Redis for 5–10 minutes. On product update invalidate category cache.

PostgreSQL indexes:

-- Composite index for typical query
CREATE INDEX ON products (category_id, brand, price)
  WHERE status = 'active';

-- GIN-index for JSONB attributes
CREATE INDEX ON products USING GIN (attributes);

Lazy loading facets: show first 5–7 values, "Show all" button loads rest separately.

Mobile Adaptation

On mobile filters hidden behind "Filters" button → opens bottom drawer (bottom sheet) fullscreen. Same components inside but with larger touch targets. "Apply" button fixed at bottom. On apply drawer closes, list updates.

Timeline

  • Basic filtering (SQL, checkboxes for 3–4 attributes, price range): 1–2 weeks
  • Faceted search on Elasticsearch (dynamic counters, all filter types, URL sync): 3–4 weeks
  • Add price histogram and aggregation caching: +1 week

Choice between SQL and Elasticsearch determined by catalog size. Up to 50,000 products well-designed SQL handles. Above — Elasticsearch makes quality difference in speed and facet richness.