Implement Faceted Search
Why faceted search
Section titled “Why faceted search”Faceted search lets users narrow results by selecting values from categories — such as filtering articles by topic, date range, or author. Graph calculates facet counts server-side, so your frontend shows accurate counts without fetching all results and computing them locally.
Step 1: Understand facet types
Section titled “Step 1: Understand facet types”Graph supports three facet types depending on the property’s data type:
| Facet type | Property type | Example |
|---|---|---|
| String facet | String, select fields | Category, Author, Tags |
| Date facet | DateTime fields | PublishDate bucketed by month |
| Number range | Numeric fields | Price ranges, rating buckets |
Step 2: Add basic string facets
Section titled “Step 2: Add basic string facets”Request facets alongside your search results. Facets appear in a separate facets section of the response.
query ArticlesWithFacets {
ArticlePage(
where: { _metadata: { status: { eq: "Published" } } }
limit: 20
) {
items {
Headline
Author
Category
}
total
facets {
Category(limit: 10, orderBy: COUNT, orderType: DESC) {
name
count
}
Author(limit: 10) {
name
count
}
}
}
} {
"data": {
"ArticlePage": {
"items": [ ... ],
"total": 156,
"facets": {
"Category": [
{ "name": "Technology", "count": 42 },
{ "name": "Business", "count": 38 },
{ "name": "Science", "count": 27 }
],
"Author": [
{ "name": "Jane Smith", "count": 15 },
{ "name": "John Doe", "count": 12 }
]
}
}
}
} Verify: Run this query in the Graph explorer. You should see a facets object in the response with Category and Author arrays, each containing name and count values. If facets return empty, confirm your content type has published items with those fields populated.
Step 3: Add date facets
Section titled “Step 3: Add date facets”Date facets bucket results by time units. Use these for “published this month” or “by year” filters.
query ArticlesByDate {
ArticlePage(
where: { _metadata: { status: { eq: "Published" } } }
limit: 20
) {
items {
Headline
_metadata { published }
}
facets {
_metadata {
published(unit: MONTH) {
name
count
}
}
}
}
} Available date units: DAY, WEEK, MONTH, YEAR.
Verify: The response should show date buckets with counts. If you use MONTH, each name value will be a month string like "2026-03". If all counts are zero, check that your content type’s DateTime field has values.
Step 4: Add number range facets
Section titled “Step 4: Add number range facets”Number ranges let users filter by price tiers, rating brackets, or other numeric groupings.
query ProductsWithPriceRanges {
ProductPage(
where: { _metadata: { status: { eq: "Published" } } }
limit: 20
) {
items {
ProductName
Price
}
facets {
Price(
ranges: [
{ from: 0, to: 25 }
{ from: 25, to: 50 }
{ from: 50, to: 100 }
{ from: 100, to: 500 }
]
) {
name
count
}
}
}
} Verify: Each range should show a count of items whose numeric value falls within the defined bounds. The name field shows the range label (e.g., "0 - 25"). If ranges overlap, items will be counted in multiple buckets.
Step 5: Combine facets with active filters
Section titled “Step 5: Combine facets with active filters”When a user selects a facet value, add it as a filter to the query while continuing to return facet counts for remaining options.
query FilteredWithFacets($selectedCategory: String) {
ArticlePage(
where: {
_metadata: { status: { eq: "Published" } }
Category: { eq: $selectedCategory }
}
limit: 20
) {
items {
Headline
Category
Author
}
total
facets {
Category(limit: 10) {
name
count
}
Author(limit: 10) {
name
count
}
}
}
} async function fetchWithFacets(selectedFilters) {
const where = {
_metadata: { status: { eq: 'Published' } }
};
if (selectedFilters.category) {
where.Category = { eq: selectedFilters.category };
}
if (selectedFilters.author) {
where.Author = { eq: selectedFilters.author };
}
const result = await graphFetch(FACETED_QUERY, { where });
return {
items: result.data.ArticlePage.items,
total: result.data.ArticlePage.total,
facets: result.data.ArticlePage.facets,
};
} Verify: With a category filter applied, the total count should be lower than without. Facet counts for the filtered field should still show all options (so users can switch), but other facets should reflect the narrowed set. If facet counts don’t change when you filter, check that the where clause is correctly applied.
Step 6: Combine facets with full-text search
Section titled “Step 6: Combine facets with full-text search”Facets work alongside full-text search. The facet counts reflect the search-filtered result set, not the entire content collection.
query SearchWithFacets($searchTerm: String!) {
ArticlePage(
where: {
_fulltext: { contains: $searchTerm }
_metadata: { status: { eq: "Published" } }
}
orderBy: { _ranking: RELEVANCE }
limit: 20
) {
items {
Headline
Category
_score
}
total
facets {
Category(limit: 10) {
name
count
}
}
}
} Verify: Search for a specific term and check that facet counts reflect only the matched results, not the entire content set. The _score field should appear on each item, confirming relevance ranking is active.
Troubleshooting: If facets return empty arrays, common causes are:
- The property is not indexed in Graph (check your content model)
- No published content has values for that field
- The field name in the facets block doesn’t match the property name exactly (case-sensitive)
Best practices
Section titled “Best practices”- Limit facet values — Use
limitto cap facet options at a reasonable number (10-20). Users cannot meaningfully choose from hundreds of options. - Order facets by count — Show the most common values first using
orderBy: COUNT, orderType: DESC. - Show selected filters clearly — Display active filter selections above the results so users can remove them easily.
- Update facets on filter change — Always re-query when the user selects or deselects a facet value. Facet counts must reflect the current filter state.
1. A product catalog page shows a sidebar with category filters. When a user selects 'Electronics', the facet counts for other categories should reflect only the Electronics subset. The developer notices facet counts are not changing when a filter is applied. What is the most likely cause?
When facets are combined with where filters, facet counts should reflect the filtered result set. If counts are not changing, the where clause is likely not being applied correctly to the query.
When facets are combined with where filters, facet counts should reflect the filtered result set. If counts are not changing, the where clause is likely not being applied correctly to the query.
Review this topic →2. A content site wants to let users filter articles by publication month using a 'Published this month' sidebar. Which facet type and configuration should the developer use?
Date facets with the MONTH unit automatically bucket results by calendar month, providing name and count values that can drive a month-based filter UI.
Date facets with the MONTH unit automatically bucket results by calendar month, providing name and count values that can drive a month-based filter UI.
Review this topic →