Private Beta
.md

BountyHub Docs

Dataset Structured Filters

Filter project dataset queries with the typed FilterNode AST: operators, AND/OR/NOT groups, value types, time ranges, history, and the UI filter builder.

Dataset structured filters

Datasets support two kinds of filtering:

  1. SQL — put a WHERE clause in your query. This is the most flexible and runs inside DuckDB.
  2. Structured filters — a typed filter tree sent alongside the query. The service compiles it into a parameterized SQL predicate, so values are bound, never interpolated.

The Hub's Filters panel builds structured filters for you. The same AST is available in QueryDatasetRequest.filter (and ExportDatasetRequest.filter), where values are bound as SQL parameters. Project-wide queries filter with SQL WHERE clauses instead.

#UI filter builder

The Query tab starts with no filters. Use Add filter, choose a column and an operator, enter a value, then press Run.

  • Match all / any combines the conditions with AND or OR.
  • Operators are limited to the selected column kind (see below).
  • in and not in accept comma-separated values.
  • Booleans use a true/false selector; timestamps use a date-time input.
  • is empty / is not empty are IS NULL / IS NOT NULL and need no value.
  • Filters are not applied live; they take effect when the query runs.

#Operators

OperatorEnumValuesCompiled predicate
IsFILTER_OP_EQ1"column" = ?
Is notFILTER_OP_NE1"column" <> ?
>FILTER_OP_GT1"column" > ?
>=FILTER_OP_GTE1"column" >= ?
<FILTER_OP_LT1"column" < ?
<=FILTER_OP_LTE1"column" <= ?
ContainsFILTER_OP_CONTAINS1strpos("column", ?) > 0
Starts withFILTER_OP_STARTS_WITH1starts_with("column", ?)
Ends withFILTER_OP_ENDS_WITH1ends_with("column", ?)
InFILTER_OP_IN1+"column" IN (?, …)
Not inFILTER_OP_NOT_IN1+"column" NOT IN (?, …)
Is emptyFILTER_OP_IS_NULL0"column" IS NULL
Is not emptyFILTER_OP_IS_NOT_NULL0"column" IS NOT NULL

Text operators are case-sensitive and literal: contains uses strpos, so % and _ have no wildcard meaning. Use SQL ILIKE if you need case-insensitive matching.

#Groups and negation

text
  • An empty AND group compiles to TRUE; an empty OR group compiles to FALSE.
  • not wraps any node: NOT (<predicate>).
  • Column names must be valid identifiers. They are quoted, and all values are parameterized.

#Where filters run

This distinction matters when your SQL aggregates or renames columns.

#Single-dataset queries and exports

QueryDataset and ExportDataset apply the structured filter outside your SELECT:

sql

So the filter sees your query's output columns:

  • With the default SELECT * FROM dataset, every schema column plus __ingested_at and __deleted is available.
  • If you project SELECT host, count(*) AS n ..., only host and n exist. Referencing severity fails; filter on the output name or move the predicate into the SQL WHERE.

#Project-wide queries

QueryDatasets does not use the structured filter builder. Filter inside the SQL with a WHERE clause:

sql

The per-relation filters field on QueryDatasetsRequest is reserved and is not supported by the current execution path.

#Views

ExecuteDatasetView has no filter or time-range fields. Put predicates in the view SQL.

#Time ranges and history

FieldApplies toNotes
ingestedAtFrom__ingested_at >= valueSame “outside your SELECT” rule as filters.
ingestedAtTo__ingested_at <= valueMust not be before ingestedAtFrom.
includeHistorySwitches the relation to raw observationsFilters and time bounds apply to history too.

The default SELECT * FROM dataset includes __ingested_at. If you project a subset and set a time range, include __ingested_at in the projection, or filter inside SQL.

The Hub's date-time inputs use the browser's local time zone. API clients send RFC 3339 timestamps.

#API examples

#AND group

json

#OR group with a negation

json

integerValue is an int64 and therefore a JSON string. Timestamps are RFC 3339 strings inside timestampValue.

#Value types

Column kindValue fieldExample
TexttextValue{"textValue":"api.example.com"}
IntegerintegerValue (string){"integerValue":"200"}
NumbernumberValue{"numberValue":9.8}
BooleanbooleanValue{"booleanValue":true}
TimestamptimestampValue{"timestampValue":"2026-01-01T00:00:00Z"}

Values must match the column kind. The UI builds the correct value type from the schema; API clients should do the same. A mismatch surfaces as a DuckDB binder or conversion error.

SQL NULL comparisons never match, so is = null is not a useful filter — use is empty (IS NULL).

#Errors

ErrorCause
Invalid dataset filterUnsupported operator, wrong number of values, or an empty value (except null checks).
DuckDB could not prepare the queryThe column does not exist in the filtered scope, or a value type does not match.
Invalid filter for dataset '<name>'A project-wide RelationFilter failed to compile against that relation.