Filters can work with strings, numbers, booleans, dates, tags, or lists.
Add filters to your UI with InstantSearch widgets or your own custom code.
Filter by string
Example dataset
Algolia lets you filter search results by string attributes. For example, users of an online bookstore might want to search for books from different publishers. With filters, they can refine results by:
- Showing books published by Penguin
- Showing books published by Bloomsbury or Scribe
- Showing all books except those published by Penguin
Apply a string filter
Set author
as an attribute for faceting, then apply your string filters with the filters
parameter in your search
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // Published by Penguin
$results = $index->search('books', [
'filters' => 'publisher:Penguin'
]);
// Published by Bloomsbury or Scribe
$results2 = $index->search('books', [
'filters' => 'publisher:Bloomsbury OR publisher:Scribe'
]);
// Everything but Penguin books
$results3 = $index->search('books', [
'filters' => 'NOT publisher:Penguin'
]);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # Published by Penguin
results = index.search('books', {
filters: 'publisher:Penguin'
})
# Published by Bloomsbury or Scribe
results2 = index.search('books', {
filters: 'publisher:Bloomsbury OR publisher:Scribe'
})
# Everything but Penguin books
results3 = index.search('books', {
filters: 'NOT publisher:Penguin'
})
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| // Published by Penguin
index.search('books', {
filters: 'publisher:Penguin'
}).then(({ hits }) => {
console.log(hits);
});
// Published by Bloomsbury or Scribe
index.search('books', {
filters: 'publisher:Bloomsbury OR publisher:Scribe'
}).then(({ hits }) => {
console.log(hits);
});
// Everything but Penguin books
index.search('books', {
filters: 'NOT publisher:Penguin'
}).then(({ hits }) => {
console.log(hits);
});
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # Published by Penguin
results = index.search("books", {
"filters": "publisher:Penguin"
})
# Published by Bloomsbury or Scribe
results2 = index.search("books", {
"filters": "publisher:Bloomsbury OR publisher:Scribe"
})
# Everything but Penguin books
results3 = index.search("books", {
"filters": "NOT publisher:Penguin"
})
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // Published by Penguin
let query = Query(query: "books")
query.filters = "publisher:Penguin"
// Published by Bloomsbury or Scribe
let query2 = Query(query: "books")
query2.filters = "publisher:Bloomsbury OR publisher:Scribe"
// Everything but Penguin books
let query3 = Query(query: "books")
query3.filters = "NOT publisher:Penguin"
index.search(query, completionHandler: { (res, error) in
print(res)
})
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| // Published by Penguin
index.search(query("books") {
filters {
and {
facet("publisher", "Penguin")
}
}
})
// Published by Bloomsbury or Scribe
index.search(query("books") {
filters {
orFacet {
facet("publisher", "Bloomsbury")
facet("publisher", "Scribe")
}
}
})
// Everything but Penguin books
index.search(query("books") {
filters {
and {
facet("brand", "Penguin", isNegated = true)
}
}
})
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // Published by Penguin
index.Search(new Query("books") {
Filters = "publisher:Penguin"
});
// Published by Bloomsbury or Scribe
index.Search(new Query("books") {
Filters = "publisher:Bloomsbury OR publisher:Scribe"
});
// Everything but Penguin books
index.Search(new Query("books") {
Filters = "NOT publisher:Penguin"
});
|
1
2
3
4
5
6
7
8
9
10
11
| // Published by Penguin
index.search(new Query("books")
.setFilters("publisher:Penguin"));
// Published by Bloomsbury or Scribe
index.search(new Query("books")
.setFilters("publisher:Bloomsbury OR publisher:Scribe"));
// Everything but Penguin books
index.search(new Query("books")
.setFilters("NOT publisher:Penguin"));
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // Published by Penguin
res, err := index.Search(
"books",
opt.Filters("publisher:Penguin"),
)
// Published by Bloomsbury or Scribe
res, err := index.Search(
"books",
opt.Filters("publisher:Bloomsbury OR publisher:Scribe"),
)
// Everything but Penguin books
res, err := index.Search(
"books",
opt.Filters("NOT publisher:Penguin"),
)
|
Filter by numeric value
Algolia lets you numerically filter results with a comparison or a range.
This only works with numeric values.
For example, you could allow users to only show books that cost less than a certain price or those in a specific price range.
The price
attribute is a numeric attribute, not a string attribute.
Apply a numeric filter
Example dataset
Using the example dataset, you’ve decided to let users define a price limit. For example, they may only want books that cost less than $10:
1
2
3
| $results = $index->search('books', [
'filters' => 'price < 10'
]);
|
1
2
3
| results = index.search('books', {
filters: 'price < 10'
})
|
1
2
3
4
5
| index.search('books', {
filters: `price < 10`
}).then(({ hits }) => {
console.log(hits);
});
|
1
2
3
| results = index.search("books", {
"filters": "price < 10"
})
|
1
2
3
4
5
6
| let query = Query(query: "books")
query.filters = "price < 10"
index.search(query, completionHandler: { (res, error) in
print(res)
})
|
1
2
3
4
5
6
7
8
9
| val query = query("books") {
filters {
and {
comparison("price", Less, 10)
}
}
}
index.search(query)
|
1
2
3
| index.Search(new Query("books") {
Filters = "price < 10"
});
|
1
2
3
4
| index.search(
new Query("books")
.setFilters("price < 10")
);
|
1
2
3
4
| res, err := index.Search(
"books",
opt.Filters("price < 10"),
)
|
1
2
3
4
5
6
| client.execute {
search into "myIndex" query Query(
query = Some("books"),
filters = Some("price < 10")
)
}
|
Algolia filters use an SQL-like syntax, which lets you use comparison operator attributes: <
, <=
, =
, !=
, >=
, and >
.
To allow users to retrieve books between a range, say $10 and $20, set a range filter:
1
2
3
| $results = $index->search('query', [
'filters' => 'price:10 TO 20'
]);
|
1
2
3
| results = index.search('books', {
filters: 'price:10 TO 20'
})
|
1
2
3
4
5
| index.search('books', {
filters: 'price:10 TO 20'
}).then(({ hits }) => {
console.log(hits);
});
|
1
2
3
| results = index.search("books", {
"filters": "price:10 TO 20"
})
|
1
2
3
4
5
6
| let query = Query(query: "books")
query.filters = "price:10 TO 20"
index.search(query, completionHandler: { (res, error) in
print(res)
})
|
1
2
3
4
5
6
7
8
9
| val query = query("books") {
filters {
and {
range("price", 10..20)
}
}
}
index.search(query)
|
1
2
3
| index.Search(new Query<Book>("books") {
Filters = "price:10 TO 20"
});
|
1
2
3
4
| index.search(
new Query("books")
.setFilters("price:10 TO 20")
);
|
1
2
3
4
| res, err := index.Search(
"books",
opt.Filters("price:10 TO 20"),
)
|
1
2
3
4
5
6
| client.execute {
search into "myIndex" query Query(
query = Some("books"),
filters = Some("price:10 TO 20")
)
}
|
Filter by date
Example dataset
As well as sorting, you can use dates to filter search results within a specific period. For example, you can allow users to filter on recently published books or only see books published within a certain period.
Algolia can filter on date attributes,
but they must be formatted as Unix timestamps.
For more information, see Formatting dates
Instead of changing the date attribute, you could add an additional timestamp attribute.
In the example dataset,
the publication_date
attribute has the formatted date for display, while the date_timestamp
attribute can be used for filtering.
Apply a date filter
With dates represented as Unix timestamp, use the filters
parameter to only retrieve some results. For example:
Recently published books
If you want users to filter for recent books, first decide what recent means to you.
For example, a recent book might be a book published less than a year ago. This means you must set a filter that excludes records with date_timestamp
greater than now minus one year.
1
2
3
4
5
| $dateTimestamp = strtotime('-1 years');
$results = $index->search('YourSearchQuery', [
'filters' => "date_timestamp > $dateTimestamp"
]);
|
1
2
3
4
5
| nowTimestamp = Time.now.to_i # Unix timestamp
results = index.search('YourSearchQuery', {
filters: "date_timestamp >= #{nowTimestamp - 60 * 60 * 24 * 365}"
})
|
1
2
3
4
5
6
7
| const d = new Date()
index.search('YourSearchQuery', {
filters: `date_timestamp > ${Math.floor(d.setDate(d.getDate() - 365) / 1000)}`
}).then(({ hits }) => {
console.log(hits);
});
|
1
2
3
4
5
6
| date = datetime.datetime.now() - datetime.timedelta(days=365)
date_timestamp = int(time.mktime(date.timetuple()))
results = index.search("YourSearchQuery", {
"filters": f"date_timestamp > {date_timestamp}"
})
|
1
2
3
4
5
6
7
8
9
| let date = Calendar.current.date(byAdding: .year, value: -1, to: Date())
let dateTimestamp = Int(date!.timeIntervalSince1970)
let query = Query(query: "YourSearchQuery")
query.filters = "date_timestamp > \(dateTimestamp)"
index.search(query, completionHandler: { (res, error) in
print(res)
})
|
1
2
3
4
5
6
7
8
9
| val query = query("YourSearchQuery") {
filters {
and {
comparison("date_timestamp", Greater, today.minusYears(1).toInstant().toEpochMilli())
}
}
}
index.search(query)
|
1
2
3
4
5
6
7
| DateTime date = DateTime.UtcNow.AddYears(-1);
DateTime sTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
long unixTime = (long)(date - sTime).TotalSeconds;
index.Search(new Query("YourSearchQuery") {
Filters = $"date_timestamp > {unixTime}"
});
|
1
2
| long unixTimeStamp = ZonedDateTime.now(ZoneOffset.UTC).plusYears(-1).toEpochSecond();
index.search(new Query().setFilters("date_timestamp > " + unixTimeStamp));
|
1
2
3
4
5
6
7
| dateTimestamp := time.Now().AddDate(-1, 0, 0).Unix()
filter := fmt.Sprintf("date_timestamp > %d", dateTimestamp)
res, err := index.Search(
"YourSearchQuery",
opt.Filters(filter),
)
|
1
2
3
4
5
6
7
8
| val dateTimestamp = LocalDateTime.now().minusYears(1).toInstant(ZoneOffset.UTC).getEpochSecond
client.execute {
search into "myIndex" query Query(
query = Some("YourSearchQuery"),
filters = Some("date_timestamp > " + dateTimestamp),
)
}
|
Algolia filters use an SQL-like syntax, which lets you use comparison operators: <
, <=
, =
, !=
, >=
, and >
.
Books for a particular year
If you want to only retrieve books from 2018, set a range filter and provide it with Unix timestamps for the first and last day of the year:
1
2
3
| $results = $index->search('YourSearchQuery', [
'filters' => 'date_timestamp:1514764800 TO 1546300799'
]);
|
1
2
3
| results = index.search('YourSearchQuery', {
filters: 'date_timestamp:1514764800 TO 1546300799'
})
|
1
2
3
4
5
| index.search('YourSearchQuery', {
filters: 'date_timestamp:1514764800 TO 1546300799'
}).then(({ hits }) => {
console.log(hits);
});
|
1
2
3
| results = index.search('YourSearchQuery', {
"filters": "date_timestamp:1514764800 TO 1546300799"
})
|
1
2
3
4
5
6
| let query = Query(query: "YourSearchQuery")
query.filters = "date_timestamp:1514764800 TO 1546300799"
index.search(query, completionHandler: { (res, error) in
print(res)
})
|
1
2
3
4
5
6
7
8
9
| val query = query("YourSearchQuery") {
filters {
and {
range("date_timestamp", 1514764800000..1546300799000)
}
}
}
index.search(query)
|
1
2
3
| index.Search(new Query("YourSearchQuery") {
Filters = "date_timestamp:1514764800 TO 1546300799"
});
|
1
2
3
4
| index.search(
new Query("YourSearchQuery")
.setFilters("date_timestamp:1514764800 TO 1546300799")
);
|
1
2
3
4
| res, err := index.Search(
"YourSearchQuery",
opt.Filters("date_timestamp:1514764800 TO 1546300799"),
)
|
1
2
3
4
5
6
| client.execute {
search into "myIndex" query Query(
query = Some("YourSearchQuery"),
filters = Some("date_timestamp:1514764800 TO 1546300799")
)
}
|
If you want to exclude a particular year or search for all books published outside a specific time you can combine time periods with the NOT
boolean operator:
1
2
3
| $results = $index->search('YourSearchQuery', [
'filters' => 'NOT date_timestamp:1514764800 TO 1546300799'
]);
|
1
2
3
| results = index.search('YourSearchQuery', {
filters: 'NOT date_timestamp:1514764800 TO 1546300799'
})
|
1
2
3
4
5
| index.search('YourSearchQuery', {
filters: 'NOT date_timestamp:1514764800 TO 1546300799'
}).then(({ hits }) => {
console.log(hits);
});
|
1
2
3
| results = index.search("YourSearchQuery", {
"filters": "NOT date_timestamp:1514764800 TO 1546300799"
})
|
1
2
3
4
5
6
| let query = Query(query: "YourSearchQuery")
query.filters = "NOT date_timestamp:1514764800 TO 1546300799"
index.search(query, completionHandler: { (res, error) in
print(res)
})
|
1
2
3
| index.Search(new Query("YourSearchQuery") {
Filters = "NOT date_timestamp:1514764800 TO 1546300799"
});
|
1
2
3
4
| index.search(
new Query("YourSearchQuery")
.setFilters("NOT date_timestamp:1514764800 TO 1546300799")
);
|
1
2
3
4
| res, err := index.Search(
"YourSearchQuery",
opt.Filters("NOT date_timestamp:1514764800 TO 1546300799"),
)
|
1
2
3
4
5
6
| client.execute {
search into "myIndex" query Query(
query = Some("YourSearchQuery"),
filters = Some("NOT date_timestamp:1514764800 TO 1546300799")
)
}
|
Closest dates
If your index contains books that will be published in the future, it can be helpful to sort results from sooner to later, so that users will see the next published books first.
First, sort records by ascending date so that books due to be published later sit lower in the search results:
1
2
3
4
5
6
7
8
9
10
11
12
13
| $index->setSettings([
'ranking' => [
'asc(date_timestamp)',
'typo',
'geo',
'words',
'filters',
'proximity',
'attribute',
'exact',
'custom'
]
]);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| index.set_settings({
ranking: [
'asc(date_timestamp)',
'typo',
'geo',
'words',
'filters',
'proximity',
'attribute',
'exact',
'custom'
]
})
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| index.setSettings({
ranking: [
"asc(date_timestamp)",
"typo",
"geo",
"words",
"filters",
"proximity",
"attribute",
"exact",
"custom"
]
}).then(() => {
// done
});
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| index.set_settings({
"ranking": [
"asc(date_timestamp)",
"typo",
"geo",
"words",
"filters",
"proximity",
"attribute",
"exact",
"custom"
]
})
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| index.setSettings([
"ranking": [
"asc(date_timestamp)",
"typo",
"geo",
"words",
"filters",
"proximity",
"attribute",
"exact",
"custom"
]
])
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| IndexSettings settings = new IndexSettings
{
Ranking = new List<string>
{
"asc(date_timestamp)",
"typo",
"geo",
"words",
"filters",
"proximity",
"attribute",
"exact",
"custom"
}
};
index.SetSettings(settings);
// Asynchronous
await index.SetSettingsAsync(settings);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| index.setSettings(
new IndexSettings().setRanking(Arrays.asList(
"asc(date_timestamp)",
"typo",
"geo",
"words",
"filters",
"proximity",
"attribute",
"exact",
"custom",
))
);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| res, err := index.SetSettings(search.Settings{
Ranking: opt.Ranking(
"asc(date_timestamp)",
"typo",
"geo",
"words",
"filters",
"proximity",
"attribute",
"exact",
"custom",
),
})
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| client.execute {
setSettings of "myIndex" `with` IndexSettings(
ranking = Some(Seq(
Ranking.asc("date_timestamp"),
Ranking.typo,
Ranking.geo,
Ranking.words,
Ranking.filters,
Ranking.proximity,
Ranking.attribute,
Ranking.exact,
Ranking.custom
))
)
}
|
Then, filter out every record with past dates:
1
2
3
4
5
| $nowTimestamp = time();
$results = $index->search('YourSearchQuery', [
'filters' => "date_timestamp >= $nowTimestamp"
]);
|
1
2
3
4
5
| nowTimestamp = Time.now.to_i
results = index.search('YourSearchQuery', {
filters: "date_timestamp >= #{nowTimestamp}"
})
|
1
2
3
4
5
6
7
| const nowTimestamp = Date.now();
index.search('YourSearchQuery', {
filters: `date_timestamp >= ${nowTimestamp}`
}).then(({ hits }) => {
console.log(hits);
});
|
1
2
3
4
5
| now_timestamp = int(time.time())
results = index.search("YourSearchQuery", {
"filters": f"date_timestamp >= {now_timestamp}"
})
|
1
2
3
4
5
6
7
8
| let nowTimestamp = NSDate().timeIntervalSince1970
let query = Query(query: "YourSearchQuery")
query.filters = "date_timestamp >= \(nowTimestamp)"
index.search(query, completionHandler: { (res, error) in
print(res)
})
|
1
2
3
4
5
| long nowTimeStamp = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
index.Search(new Query("YourSearchQuery") {
Filters = $"date_timestamp > {nowTimeStamp}"
});
|
1
2
| long nowTimeStamp = OffsetDateTime.now(ZoneOffset.UTC).toEpochSecond();
index.search(new Query().setFilters("date_timestamp >= " + nowTimeStamp));
|
1
2
3
4
5
6
7
| nowTimestamp := time.Now().Unix()
filter := fmt.Sprintf("date_timestamp > %d", nowTimestamp)
res, err := index.Search(
"YourSearchQuery",
opt.Filters(filter),
)
|
1
2
3
4
5
6
7
8
| val nowTimestamp = LocalDateTime.now().toInstant(ZoneOffset.UTC).getEpochSecond
client.execute {
search into "myIndex" query Query(
query = Some("YourSearchQuery"),
filters = Some("date_timestamp > " + nowTimestamp),
)
}
|
Filter by array
Example dataset
Some attributes, such as the genre of a book, are lists of values. One book can belong to multiple genres.
Hence, the genre attribute should be an array.
If you have a chain of bookstores with an accompanying ecommerce website, you may want to let users filter by book genre and store. To do this, the example dataset has two array attributes: store
and categories
.
Using this dataset, users could, for example, retrieve all books about politics in stock in The Corner Bookshop.
Apply an array filter
Once you’ve set categories
and store
as attributes for faceting, apply string filters with the filters
parameter in your search
code:
1
2
3
| $results = $index->search('ben', [
'filters' => 'categories:politics AND store:Gibert Joseph Saint-Michel'
]);
|
1
2
3
| results = index.search('ben', {
filters: 'categories:politics AND store:Gibert Joseph Saint-Michel'
})
|
1
2
3
4
5
| index.search('ben', {
filters: 'categories:politics AND store:Gibert Joseph Saint-Michel'
}).then(({ hits }) => {
console.log(hits);
});
|
1
2
3
| results = index.search("ben", {
"filters": "categories:politics AND store:Gibert Joseph Saint-Michel"
})
|
1
2
3
4
5
6
| let query = Query(query: "harry")
query.filters = "categories:politics AND store:Gibert Joseph Saint-Michel"
index.search(query, completionHandler: { (res, error) in
print(res)
})
|
1
2
3
4
5
6
7
8
9
10
| val query = query("ben") {
filters {
and {
facet("categories", "politics")
facet("store", "Gibert Joseph Saint-Michel")
}
}
}
index.search(query)
|
1
2
3
| index.Search(new Query("ben") {
Filters = "categories:politics AND store:Gibert Joseph Saint-Michel"
});
|
1
2
3
4
| index.search(
new Query("ben")
.setFilters("categories:politics AND store:Gibert Joseph Saint-Michel")
);
|
1
2
3
4
| res, err := index.Search(
"ben",
opt.Filters("categories:politics AND store:Gibert Joseph Saint-Michel"),
)
|
1
2
3
4
5
6
| client.execute {
search into "myIndex" query Query(
query = Some("ben"),
filters = Some("categories:politics AND store:Gibert Joseph Saint-Michel")
)
}
|
Filter by boolean
Example dataset
Algolia lets you filter results by boolean attributes.
For example, you can use the is_available
boolean attribute in the example dataset to exclude all records where is_available
is false
. To do this, first declare is_available
as an attribute for faceting.
Apply a boolean filter
If you want users to see only the available books, do the following:
1
2
3
| $results = $index->search('books', [
'filters' => 'is_available:true'
]);
|
1
2
3
| results = index.search('books', {
filters: 'is_available:true'
})
|
1
2
3
4
5
| index.search('books', {
filters: `is_available:true`
}).then(({ hits }) => {
console.log(hits);
});
|
1
2
3
| results = index.search("books", {
"filters": "is_available:true"
})
|
1
2
3
4
5
6
| let query = Query(query: "books")
query.filters = "is_available:true"
index.search(query, completionHandler: { (res, error) in
print(res)
})
|
1
2
3
4
5
6
7
8
9
| val query = query("books") {
filters {
and {
facet("is_available", true)
}
}
}
index.search(query)
|
1
2
3
| index.Search(new Query<Book>("books") {
Filters = "is_available:true"
});
|
1
2
3
4
| index.search(
new Query("books")
.setFilters("is_available:true")
);
|
1
2
3
4
| res, err := index.Search(
"books",
opt.Filters("is_available:true"),
)
|
1
2
3
4
5
6
| client.execute {
search into "myIndex" query Query(
query = Some("books"),
filters = Some("is_available:true")
)
}
|
The engine considers booleans as integers: false
as 0
and true
as 1
. This means you can apply numeric filters for boolean attributes. With the example dataset, is_available=0
is the same as is_available:false
.
If creating numeric or boolean filters, you don’t need to declare the attribute as attributesForFaceting
.
Example dataset
Sometimes, you may want to filter search results based on specific metadata, like a type or a category.
Using the example dataset, the accompanying online bookstore has fiction and non-fiction sections.
Depending on which section users are searching from, you can provide a context-sensitive search experience.
For example, a user goes to the website’s non-fiction section, then starts searching for the biography of President Harry S. Truman.
If your search relevance is primarily based on popularity, by typing “harry”, they might retrieve Harry Potter books first, which wouldn’t make sense to them.
Instead, what you can do is filter results based on what they most likely want to find.
Algolia lets you add tags to your records with the reserved _tags
attribute.
Using the example dataset, if users type “harry” with the search restricted to “non-fiction”, it would retrieve “Where the Buck Stops” because it has “non-fiction” in the _tags
attribute and contains the word “harry” in the record.
1
2
3
| $results = $index->search('harry', [
'filters' => 'non-fiction' // Same as '_tags:non-fiction'
]);
|
1
2
3
| results = index.search('harry', {
filters: 'non-fiction' # Same as '_tags:non-fiction'
})
|
1
2
3
4
5
| index.search('harry', {
filters: 'non-fiction' // Same as '_tags:non-fiction'
}).then(({ hits }) => {
console.log(hits);
});
|
1
2
3
| results = index.search("harry", {
"filters": "non-fiction" # Same as "_tags:non-fiction"
})
|
1
2
3
4
5
6
| let query = Query(query: "harry")
query.filters = "non-fiction" // Same as "_tags:non-fiction"
index.search(query, completionHandler: { (res, error) in
print(res)
})
|
1
2
3
4
5
6
7
8
9
| val query = query("harry") {
filters {
and {
tag("non-fiction") // Same as "_tags:non-fiction"
}
}
}
index.search(query)
|
1
2
3
| index.Search(new Query<JObject>("harry") {
Filters = "non-fiction" // Same as "_tags:non-fiction"
});
|
1
2
3
4
| index.search(
new Query("harry")
.setFilters("non-fiction") // Same as "_tags:non-fiction"
);
|
1
2
3
4
| res, err := index.Search(
"harry",
opt.Filters("non-fiction"), // Same as "_tags:non-fiction"
)
|
1
2
3
4
5
6
| client.execute {
search into "myIndex" query Query(
query = Some("harry"),
filters = Some("non-fiction") // Same as "_tags:non-fiction"
)
}
|
If you don’t specify an attribute name, the filter is assumed to apply to the _tags
attribute. For example, fiction
translates into _tags:fiction
.
You can also use tagFilters
to do the same thing.
It’s important to consider the following when deciding whether to use the Algolia _tags
attribute or a custom attribute for faceting:
_tags
is a reserved attribute which means it automatically works as a string filter without you having to set it as an attribute for faceting or use the filterOnly
modifier.
_tags
isn’t searchable by default.
- You can’t use
_tags
for non-filtering purposes, such as displaying in search results or computing counts of records that match the filters.
_tags
can only contain strings.
In short, if you have several types of string filters or any non-string filters, creating a custom attribute is usually the way to go.
Filter by null or missing attributes
Since Algolia doesn’t support filtering on null
values or missing attributes, what happens when your index contains an attribute that isn’t present in all records?
For example, consider an online bookstore where people can buy and rate books from 0 to 5. Any record without the rating
attribute is assumed to be unrated.
If you want users to search for both rated and unrated books in the same filter, you must modify your data.
To do this, you can take one of two approaches:
Create a tag
Example dataset
At indexing time, you can add a tag value to indicate if a record is or isn’t rated. In the example dataset, some records have a rating
attribute and value, others have a null rating
, and some don’t have a rating
attribute.
A null
or nonexistent attribute is different from zero, which represents a book with the lowest rating.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| [
{
// ...
"rating": 5,
"_tags": ["is_rated"]
},
{
// ...
"rating": null,
"_tags": ["is_not_rated"]
},
{
// ...
"_tags": ["is_not_rated"]
}
]
|
To search for records without the attribute or have a null value, you can now use tags filtering.
Create a boolean attribute
At indexing time, you can add a boolean value to indicate if a record is or isn’t rated:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| [
{
// ...
"rating": 5,
"is_rated": true
},
{
// ...
"rating": null,
"is_rated": false
},
{
// ...
"is_rated": false
}
]
|
To search for records without the attribute or have a null value, you can now use boolean filtering.
Filter by objectID
By default, the engine sets a record’s objectID
attribute as a filter-only facet.
This means you can use the filters
parameter to filter on objectID
.
This is helpful when you want to include or exclude specific records in the current search.
For example, to exclude the record with objectID
“1234”, use the filter NOT objectID:1234
in the filters
parameter of your search.
Example dataset
All the examples on this page use a bookstore index: books
. The index has records that look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
| [
{
"title": "Harry Potter and the Philosopher's Stone",
"author": "J. K. Rowling",
"publisher": "Bloomsbury",
"price": 7.94,
"publication_date": "1996-06-17",
"date_timestamp": 866505600,
"is_available": true,
"rating": 5,
"_tags": [
"fiction",
"is_rated"
],
"popularity": 1000,
"store": [
"The Corner Bookshop",
"Gibert Joseph Barbès",
"Gibert Joseph Paris 13 - Grande Bibliothèque"
],
"categories": [
"fantasy",
"science fiction",
"children's literature"
]
},
{
"title": "A Perfect Crime",
"author": "Peter Abrahams",
"publisher": "Penguin",
"price": 7.94,
"publication_date": "1998-09-16",
"date_timestamp": 905904000,
"is_available": true,
"rating": null,
"_tags": [
"fiction",
"is_not_rated"
],
"popularity": 800,
"store": [
"The Corner Bookshop",
"Gibert Joseph Barbès"
],
"categories": [
"thriller",
"crime fiction"
]
},
{
"title": "The World as It Is",
"author": "Ben Rhodes",
"publisher": "Penguin",
"price": 9.54,
"publication_date": "2018-06-05",
"date_timestamp": 1528156800,
"is_available": false,
"_tags": [
"non-fiction",
"is_not_rated"
],
"popularity": 900,
"store": [
"The Corner Bookshop"
],
"categories": [
"history",
"politics"
]
},
{
"title": "Yellowface",
"author": "R.F. Kuang",
"publisher": "The Borough Press",
"price": 9.19,
"publication_date": "2023-05-16",
"date_timestamp": 1684108800,
"is_available": true,
"_tags": [
"fiction",
"is_not_rated"
],
"popularity": 900,
"store": [
"The Corner Bookshop"
],
"categories": [
"dark humor",
"satire"
]
},
{
"title": "A Fighting Chance",
"author": "Elizabeth Warren",
"publisher": "Scribe",
"price": 12.97,
"publication_date": "2014-04-22",
"date_timestamp": 1398124800,
"is_available": false,
"rating": 5,
"_tags": [
"non-fiction",
"is_rated"
],
"popularity": 800,
"store": [
"The Corner Bookshop"
],
"categories": [
"history",
"politics"
]
},
{
"title": "Where the Buck Stops",
"author": "Harry S Truman",
"publisher": "Warner Books",
"price": 15.014,
"publication_date": "1990-10-01",
"date_timestamp": 654739200,
"is_available": true,
"_tags": [
"non-fiction",
"is_not_rated"
],
"popularity": 800,
"store": [
"The Corner Bookshop"
],
"categories": [
"history",
"politics",
"biography"
]
},
]
|