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:
The product field to filter on. Use dot notation for nested metadata fields: metadata.color.
The comparison operator. See Operators below.
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
{ 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
| Operator | Description | Value Type | Example |
|---|
eq | Equals | any | { field: 'brand', operator: 'eq', value: 'Nike' } |
ne | Not equals | any | { field: 'status', operator: 'ne', value: 'discontinued' } |
gt | Greater than | number | { field: 'price', operator: 'gt', value: 50 } |
gte | Greater than or equal | number | { field: 'stock', operator: 'gte', value: 1 } |
lt | Less than | number | { field: 'price', operator: 'lt', value: 100 } |
lte | Less than or equal | number | { field: 'rating', operator: 'lte', value: 5 } |
in | In array | array | { field: 'size', operator: 'in', value: ['S', 'M', 'L'] } |
nin | Not in array | array | { field: 'tag', operator: 'nin', value: ['test'] } |
exists | Field exists | boolean | { field: 'salePrice', operator: 'exists', value: true } |
match | Text contains | string | { 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.
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('');
}
- 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