Skip to main content

Overview

Filters narrow search and recommendation results based on product attributes. Use filters for price ranges, categories, availability, and custom metadata.

Basic Syntax

const results = await refine.search.text({
  query: 'summer dress',
  topK: 24,
  filters: [
    { field: 'price', operator: 'lte', value: 200 }
  ]
});
Each filter has three properties:
field
string
required
The product field to filter on. Use dot notation for nested metadata fields: metadata.color.
operator
string
required
The comparison operator. See Operators below.
value
any
required
The value to compare against. Type depends on the operator.

Operators

Equality

  • eq (equals)
  • ne (not equals)
{ field: 'metadata.brand', operator: 'eq', value: 'Nike' }
Exact match. Case-sensitive for strings.

Comparison

  • gt (greater than)
  • gte (greater than or equal)
  • lt (less than)
  • lte (less than or equal)
{ field: 'price', operator: 'gt', value: 50 }
Greater than (exclusive).

Array Operators

  • in (in array)
  • nin (not in array)
{ field: 'metadata.color', operator: 'in', value: ['red', 'blue', 'green'] }
Field value is one of the provided values.

Existence

{ field: 'metadata.salePrice', operator: 'exists', value: true }
Check if a field exists (true) or doesn’t exist (false).

Text Matching

{ field: 'title', operator: 'match', value: 'organic' }
Partial text match within the field. Case-insensitive.

Operator Reference

OperatorDescriptionValue TypeExample
eqEqualsany{ field: 'brand', operator: 'eq', value: 'Nike' }
neNot equalsany{ field: 'status', operator: 'ne', value: 'discontinued' }
gtGreater thannumber{ field: 'price', operator: 'gt', value: 50 }
gteGreater than or equalnumber{ field: 'stock', operator: 'gte', value: 1 }
ltLess thannumber{ field: 'price', operator: 'lt', value: 100 }
lteLess than or equalnumber{ field: 'rating', operator: 'lte', value: 5 }
inIn arrayarray{ field: 'size', operator: 'in', value: ['S', 'M', 'L'] }
ninNot in arrayarray{ field: 'tag', operator: 'nin', value: ['test'] }
existsField existsboolean{ field: 'salePrice', operator: 'exists', value: true }
matchText containsstring{ field: 'description', operator: 'match', value: 'cotton' }

Common Patterns

Price Range

filters: [
  { field: 'price', operator: 'gte', value: 50 },
  { field: 'price', operator: 'lte', value: 200 }
]

In Stock Only

filters: [
  { field: 'stock', operator: 'gt', value: 0 }
]

Multiple Categories

filters: [
  { field: 'metadata.category', operator: 'in', value: ['dresses', 'skirts', 'tops'] }
]

Exclude Sale Items

filters: [
  { field: 'metadata.onSale', operator: 'ne', value: true }
]

Has Reviews

filters: [
  { field: 'metadata.reviewCount', operator: 'gte', value: 1 }
]

Brand Exclusion

filters: [
  { field: 'metadata.brand', operator: 'nin', value: ['Generic', 'Unknown'] }
]

Filter Logic

Multiple filters are combined with AND logic. All conditions must be true for a product to be included.
// Products where:
// - price is between $50-$200 AND
// - color is red, blue, or green AND
// - in stock
filters: [
  { field: 'price', operator: 'gte', value: 50 },
  { field: 'price', operator: 'lte', value: 200 },
  { field: 'metadata.color', operator: 'in', value: ['red', 'blue', 'green'] },
  { field: 'stock', operator: 'gt', value: 0 }
]
OR logic isn’t directly supported. Use the in operator for “field equals A OR field equals B” scenarios.

Metadata Fields

Access nested metadata using dot notation:
// Product structure
{
  productId: 'sku_001',
  title: 'Summer Dress',
  price: 79.99,
  metadata: {
    brand: 'Fashion Co',
    color: 'red',
    sizes: ['S', 'M', 'L'],
    details: {
      material: 'cotton',
      origin: 'Italy'
    }
  }
}

// Filter examples
{ field: 'metadata.brand', operator: 'eq', value: 'Fashion Co' }
{ field: 'metadata.color', operator: 'in', value: ['red', 'blue'] }
{ field: 'metadata.details.material', operator: 'eq', value: 'cotton' }

Sorting

Combine filters with sorting:
const results = await refine.search.text({
  query: 'shoes',
  topK: 24,
  filters: [
    { field: 'price', operator: 'gte', value: 50 },
    { field: 'stock', operator: 'gt', value: 0 }
  ],
  sortBy: {
    field: 'price',
    order: 'ascending'  // 'ascending' | 'descending'
  }
});
Available sort fields depend on your catalog schema. Common options:
  • price
  • metadata.rating
  • metadata.popularity
  • metadata.createdAt
Sorting by relevance (default) uses the AI ranking. Sorting by other fields overrides the AI ranking.

Filter Options in Response

Search responses include available filter values:
const results = await refine.search.text({ query: 'dress', topK: 24 });

console.log(results.filterOptions);
// [
//   { field: 'metadata.color', values: ['red', 'blue', 'black', ...] },
//   { field: 'metadata.size', values: ['XS', 'S', 'M', 'L', 'XL'] },
//   { field: 'metadata.brand', values: ['Brand A', 'Brand B', ...] }
// ]
Use this to build dynamic filter UIs:
function buildFilterUI(filterOptions: FilterOption[]) {
  return filterOptions.map(option => `
    <div class="filter-group">
      <h4>${formatFieldName(option.field)}</h4>
      ${option.values.map(value => `
        <label>
          <input type="checkbox" 
                 data-field="${option.field}" 
                 data-value="${value}" />
          ${value}
        </label>
      `).join('')}
    </div>
  `).join('');
}

Performance Tips

  • Filter on indexed fields for best performance
  • Use in with small arrays (under 100 values)
  • Avoid match on large text fields when possible
  • Combine price ranges into a single range filter

Next Steps