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. { field : 'metadata.brand' , operator : 'ne' , value : 'Generic' }
Excludes exact matches.
Comparison
{ field : 'price' , operator : 'gt' , value : 50 }
Greater than (exclusive). { field : 'price' , operator : 'gte' , value : 50 }
Greater than or equal (inclusive). { field : 'price' , operator : 'lt' , value : 100 }
Less than (exclusive). { field : 'price' , operator : 'lte' , value : 100 }
Less than or equal (inclusive).
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. { field : 'metadata.category' , operator : 'nin' , value : [ 'clearance' , 'discontinued' ] }
Field value is NOT 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 eqEquals any { field: 'brand', operator: 'eq', value: 'Nike' }neNot equals any { field: 'status', operator: 'ne', value: 'discontinued' }gtGreater than number { field: 'price', operator: 'gt', value: 50 }gteGreater than or equal number { field: 'stock', operator: 'gte', value: 1 }ltLess than number { field: 'price', operator: 'lt', value: 100 }lteLess than or equal number { field: 'rating', operator: 'lte', value: 5 }inIn array array { field: 'size', operator: 'in', value: ['S', 'M', 'L'] }ninNot in array array { field: 'tag', operator: 'nin', value: ['test'] }existsField exists boolean { field: 'salePrice', operator: 'exists', value: true }matchText 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
Text Search Search with text queries
Recommendations Filter recommendations too