Skip to content

Filter

import { Filter } from '@dxos/echo';

Build a predicate, then pass it to db.query directly or through Query.select. Every builder is O(1): it creates an AST node and matches nothing until the query runs.

Member Signature Summary
type (type, props?) => Filter<T> Objects of a type, optionally by props
props (props) => Filter<T> Objects whose fields match
eq neq (value) => Filter<T> Equal, not equal
gt gte lt lte (value) => Filter<T> Ordered comparison
between (from, to) => Filter<T> From inclusive, to exclusive
contains (value) => Filter<readonly T[]> Array field holds the value
in (...values) => Filter<T> Field equals one of the values
and or not (...filters) => Filter<T> Boolean combinators
text (text, options?) => Filter Full-text or vector search
created updated ({ after?, before? }) => Filter Timestamp range
childOf (parents, options?) => Filter Children of an object
changes (targets?) => Filter Changes instead of objects

type takes an ECHO type and an optional props shape, so field names and value types are checked. props matches on shape alone.

import {
import Filter
Filter
} from '@dxos/echo';
import {
class Person
Person
} from './schema.ts';
const
const adas: Filter.Filter<Person & OfKind<EntityKind.Object>>
adas
=
import Filter
Filter
.
const type: <typeof Person>(type: typeof Person, props?: Filter.Props<Person & OfKind<EntityKind.Object>> | undefined) => Filter.Filter<Person & OfKind<EntityKind.Object>> (+4 overloads)
type
(
class Person
Person
, {
name?: string | Filter.Filter<string> | undefined
name
: 'Ada' });
const
const untyped: Filter.Filter<{
name: string;
}>
untyped
=
import Filter
Filter
.
const props: <{
name: string;
}>(props: Filter.Props<{
name: string;
}>) => Filter.Filter<{
name: string;
}>

Filter by properties.

@performance ― O(p) in the number of predicates; builds the AST without matching anything.

props
<{
name: string
name
: string }>({
name?: string | Filter.Filter<string> | undefined
name
: 'Ada' });

Comparators go in the props shape, on the field they test.

import {
import Filter
Filter
} from '@dxos/echo';
import {
class Person
Person
} from './schema.ts';
const
const atExample: Filter.Filter<Person & OfKind<EntityKind.Object>>
atExample
=
import Filter
Filter
.
const type: <typeof Person>(type: typeof Person, props?: Filter.Props<Person & OfKind<EntityKind.Object>> | undefined) => Filter.Filter<Person & OfKind<EntityKind.Object>> (+4 overloads)
type
(
class Person
Person
, {
email?: string | Filter.Filter<string | undefined> | undefined
email
:
import Filter
Filter
.
in<string>(...values: string[]): Filter.Filter<string> (+1 overload)
export in

Predicate for property to be in the provided array, or in the set of values projected from a subquery's results (an uncorrelated col IN (SELECT property FROM ...) semi-join — see Query.project). The subquery may target a different scope than the parent query; it is resolved once at execution time.

@param ― values - Values to check against, or a single subquery projection.

@performance ― O(1); builds a filter AST node without matching anything.

in
('ada@example.com', 'grace@example.com'),
});
import {
import Filter
Filter
,
import Query
Query
} from '@dxos/echo';
import {
class Person
Person
} from './schema.ts';
const
const peopleNotAda: Filter.Filter<Person & OfKind<EntityKind.Object>>
peopleNotAda
=
import Filter
Filter
.
const and: <[Filter.Filter<Person & OfKind<EntityKind.Object>>, Filter.Filter<Person & OfKind<EntityKind.Object>>]>(filters_0: Filter.Filter<Person & OfKind<EntityKind.Object>>, filters_1: Filter.Filter<Person & OfKind<EntityKind.Object>>) => Filter.Filter<Person & OfKind<EntityKind.Object>>

Combine filters with a logical AND.

@performance ― O(k) in the number of filters; builds the AST without matching anything.

and
(
import Filter
Filter
.
const type: <typeof Person>(type: typeof Person, props?: Filter.Props<Person & OfKind<EntityKind.Object>> | undefined) => Filter.Filter<Person & OfKind<EntityKind.Object>> (+4 overloads)
type
(
class Person
Person
),
import Filter
Filter
.
const not: <Filter.Filter<Person & OfKind<EntityKind.Object>>>(filter: Filter.Filter<Person & OfKind<EntityKind.Object>>) => Filter.Filter<Person & OfKind<EntityKind.Object>>

Negate the filter.

@performance ― O(1); builds a filter AST node without matching anything.

not
(
const adas: Filter.Filter<Person & OfKind<EntityKind.Object>>
adas
));
const
const results: (Person & OfKind<EntityKind.Object>)[]
results
= await
const db: Database.Database
db
.
Database.query: Database.QueryFn
<Query.Query<Person & OfKind<EntityKind.Object>>>(query: Query.Query<Person & OfKind<EntityKind.Object>>) => QueryResult<Person & OfKind<EntityKind.Object>> (+1 overload)
query
(
import Query
Query
.
const select: <Filter.Filter<Person & OfKind<EntityKind.Object>>>(filter: Filter.Filter<Person & OfKind<EntityKind.Object>>) => Query.Query<Person & OfKind<EntityKind.Object>>

Select objects based on a filter.

@param ― filter - Filter to select the objects.

@returns ― Query for the selected objects.

@performance ― O(1); wraps the current AST in a new immutable node without executing anything.

select
(
const peopleNotAda: Filter.Filter<Person & OfKind<EntityKind.Object>>
peopleNotAda
)).
QueryResult<Person & OfKind<EntityKind.Object>>.run(opts?: RunOptions): Promise<(Person & OfKind<EntityKind.Object>)[]>

Returns all known results.

@performance ― Async; executes the full query (index plus working set) on every call, not cached; O(n) in the data the executor examines, not in the result count.

run
();

options.type selects full-text or vector.

import {
import Filter
Filter
} from '@dxos/echo';
const
const matches: Filter.Any
matches
=
import Filter
Filter
.
const text: (text: string, options?: Filter.TextSearchOptions) => Filter.Any

Full-text or vector search.

@performance ― O(1); builds a filter AST node without matching anything.

text
('product launch', {
type?: "full-text" | "vector" | undefined
type
: 'full-text' });

Both bounds accept a number of milliseconds or a Date. With both set, the filter is the AND of the two.

import {
import Filter
Filter
} from '@dxos/echo';
const
const recent: Filter.Any
recent
=
import Filter
Filter
.
const updated: (range: TimeRange) => Filter.Any

Filter objects by updatedAt timestamp.

@performance ― O(1); builds a filter AST node without matching anything.

updated
({
after?: number | Date | undefined
after
: new
var Date: DateConstructor
new (value: number | string | Date) => Date (+3 overloads)
Date
('2026-11-01') });

childOf matches the children of one or more objects, and their children in turn unless transitive is false. It takes objects or references, and reads a reference’s URI without loading the target.

import {
import Filter
Filter
} from '@dxos/echo';
const
const owned: Filter.Any
owned
=
import Filter
Filter
.
const childOf: (parents: Unknown | Unknown | readonly (Unknown | Unknown)[], options?: Filter.ChildOfOptions) => Filter.Any

Filter objects that are children of the specified parent(s). Accepts ECHO objects, Refs, or arrays of either. Refs are resolved to DXNs without loading; objects use

Obj.getURI

. With transitive=true (default), also matches grandchildren and beyond.

@performance ― O(k) in the number of parents; refs are read by URI without loading.

childOf
(
const launch: Event
launch
); // children, grandchildren and on
const
const direct: Filter.Any
direct
=
import Filter
Filter
.
const childOf: (parents: Unknown | Unknown | readonly (Unknown | Unknown)[], options?: Filter.ChildOfOptions) => Filter.Any

Filter objects that are children of the specified parent(s). Accepts ECHO objects, Refs, or arrays of either. Refs are resolved to DXNs without loading; objects use

Obj.getURI

. With transitive=true (default), also matches grandchildren and beyond.

@performance ― O(k) in the number of parents; refs are read by URI without loading.

childOf
(
const launch: Event
launch
, {
transitive?: boolean | undefined

Whether to match transitively (grandchildren, etc.). Defaults to true.

transitive
: false });

changes selects the changes to some objects, or to every object in the space, instead of the objects. Order them by time, or count them with an aggregate.

import {
import Filter
Filter
,
import Query
Query
} from '@dxos/echo';
const
const history: Query.Query<{
readonly key: string;
readonly source: "document" | "feed";
readonly time: number;
readonly actor: string;
readonly seq: number;
readonly ops: number;
} & Query.RecordResult>
history
=
import Query
Query
.
const select: <Filter.Filter<{
readonly key: string;
readonly source: "document" | "feed";
readonly time: number;
readonly actor: string;
readonly seq: number;
readonly ops: number;
} & Query.RecordResult>>(filter: Filter.Filter<{
readonly key: string;
readonly source: "document" | "feed";
readonly time: number;
readonly actor: string;
readonly seq: number;
readonly ops: number;
} & Query.RecordResult>) => Query.Query<{
readonly key: string;
readonly source: "document" | "feed";
readonly time: number;
readonly actor: string;
readonly seq: number;
readonly ops: number;
} & Query.RecordResult>

Select objects based on a filter.

@param ― filter - Filter to select the objects.

@returns ― Query for the selected objects.

@performance ― O(1); wraps the current AST in a new immutable node without executing anything.

select
(
import Filter
Filter
.
const changes: (targets?: Unknown | Unknown | readonly (Unknown | Unknown)[]) => Filter.Filter<Change>

Select Automerge changes instead of objects: one

Change.Change

per change to the documents holding targets, or to every document in the space when called with no argument.

Changes belong to documents, not entities. Entities that share a document share its changes, and content held by another entity (a document's Text) needs its own target. Only the host answers these queries; a space-wide query must aggregate, and the index answers it only at hour granularity (see Aggregate.time).

@example

Query.select(Filter.changes()).aggregate({ day: Aggregate.time('time', 'day'), changes: Aggregate.count() });
Query.select(Filter.changes([doc, doc.content])).orderBy(Order.property('time', 'desc')).limit(50);

@performance ― O(k) in the number of targets; refs are read by URI without loading.

changes
([
const launch: Event
launch
])).
Query<{ readonly key: string; readonly source: "document" | "feed"; readonly time: number; readonly actor: string; readonly seq: number; readonly ops: number; } & RecordResult>.limit(limit: number): Query.Query<{
readonly key: string;
readonly source: "document" | "feed";
readonly time: number;
readonly actor: string;
readonly seq: number;
readonly ops: number;
} & Query.RecordResult>

Limit the number of results.

@param ― limit - Maximum number of results to return.

@returns ― Query for the limited results.

@performance ― O(1); wraps the current AST in a new immutable node without executing anything.

limit
(50);