Skip to content

Querying

By the end of this page the app will list its records sorted, search them, and find the people who work at an organization.

A query has two parts. A filter says which objects match: by type, by field values, by text. A query wraps the filter and adds what to do with the matches: their order, a limit, or a step to the objects they reference or that reference them.

A query is a value. Building one runs nothing; db.query(query) runs it against the database on the device, so a query never waits on the network. run returns the matches once. subscribe returns them, then runs again whenever an object that could match changes, whichever peer changed it.

The client returns typed objects only for the types it knows. The app passes its types to the client when it starts, in Installation.

The Filter reference lists every comparison and combinator.

  1. List each type, sorted. Filter.type selects the objects of a type, and orderBy sorts them by a field.

    export const
    const organizations: Query.Query<Organization & OfKind<EntityKind.Object>>
    organizations
    =
    import Query
    Query
    .
    const select: <Filter.Filter<Organization & OfKind<EntityKind.Object>>>(filter: Filter.Filter<Organization & OfKind<EntityKind.Object>>) => Query.Query<Organization & 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
    (
    import Filter
    Filter
    .
    const type: <typeof Organization>(type: typeof Organization, props?: Filter.Props<Organization & OfKind<EntityKind.Object>> | undefined) => Filter.Filter<Organization & OfKind<EntityKind.Object>> (+4 overloads)
    type
    (
    class Organization
    Organization
    )).
    Query<Organization & OfKind<EntityKind.Object>>.orderBy(order_0: Order.Order<Organization & OfKind<EntityKind.Object>>, ...order: Order.Order<Organization & OfKind<EntityKind.Object>>[]): Query.Query<Organization & OfKind<EntityKind.Object>>

    Order the query results. Orders are specified in priority order. The first order will be applied first, etc.

    Order.property orders by the current result shape's fields, so it works both before and after an

    aggregate

    : before, by member (row) properties; after, by the flat record's fields (any group or aggregate field — e.g. Order.property('lastMessageAt') reorders the groups by that aggregate).

    @param ― order - Order to sort the results.

    @returns ― Query for the ordered results.

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

    orderBy
    (
    import Order
    Order
    .
    const property: <Organization>(property: "website" | "name" | "~@dxos/echo/Kind" | "id", direction: OrderDirection) => Order.Order<Organization>

    Order by a property of the current result shape.

    @performance ― O(1); builds an order AST node without sorting anything.

    property
    <
    class Organization
    Organization
    >('name', 'asc'),
    );
    export const
    const people: Query.Query<Person & OfKind<EntityKind.Object>>
    people
    =
    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
    (
    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
    )).
    Query<Person & OfKind<EntityKind.Object>>.orderBy(order_0: Order.Order<Person & OfKind<EntityKind.Object>>, ...order: Order.Order<Person & OfKind<EntityKind.Object>>[]): Query.Query<Person & OfKind<EntityKind.Object>>

    Order the query results. Orders are specified in priority order. The first order will be applied first, etc.

    Order.property orders by the current result shape's fields, so it works both before and after an

    aggregate

    : before, by member (row) properties; after, by the flat record's fields (any group or aggregate field — e.g. Order.property('lastMessageAt') reorders the groups by that aggregate).

    @param ― order - Order to sort the results.

    @returns ― Query for the ordered results.

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

    orderBy
    (
    import Order
    Order
    .
    const property: <Person>(property: "name" | "~@dxos/echo/Kind" | "id" | "email" | "employer", direction: OrderDirection) => Order.Order<Person>

    Order by a property of the current result shape.

    @performance ― O(1); builds an order AST node without sorting anything.

    property
    <
    class Person
    Person
    >('name', 'asc'));
    export const
    const events: Query.Query<Event & OfKind<EntityKind.Object>>
    events
    =
    import Query
    Query
    .
    const select: <Filter.Filter<Event & OfKind<EntityKind.Object>>>(filter: Filter.Filter<Event & OfKind<EntityKind.Object>>) => Query.Query<Event & 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
    (
    import Filter
    Filter
    .
    const type: <typeof Event>(type: typeof Event, props?: Filter.Props<Event & OfKind<EntityKind.Object>> | undefined) => Filter.Filter<Event & OfKind<EntityKind.Object>> (+4 overloads)
    type
    (
    class Event
    Event
    )).
    Query<Event & OfKind<EntityKind.Object>>.orderBy(order_0: Order.Order<Event & OfKind<EntityKind.Object>>, ...order: Order.Order<Event & OfKind<EntityKind.Object>>[]): Query.Query<Event & OfKind<EntityKind.Object>>

    Order the query results. Orders are specified in priority order. The first order will be applied first, etc.

    Order.property orders by the current result shape's fields, so it works both before and after an

    aggregate

    : before, by member (row) properties; after, by the flat record's fields (any group or aggregate field — e.g. Order.property('lastMessageAt') reorders the groups by that aggregate).

    @param ― order - Order to sort the results.

    @returns ― Query for the ordered results.

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

    orderBy
    (
    import Order
    Order
    .
    const property: <Event>(property: "~@dxos/echo/Kind" | "id" | "description" | "attendees" | "title", direction: OrderDirection) => Order.Order<Event>

    Order by a property of the current result shape.

    @performance ― O(1); builds an order AST node without sorting anything.

    property
    <
    class Event
    Event
    >('title', 'asc'));
  2. Run a query. The results are typed, so person.name is a string.

    const
    const everyone: (Person & OfKind<EntityKind.Object>)[]
    everyone
    = await
    const db: Database.Database
    db
    .
    Database.query: Database.QueryFn
    <Query<Person & OfKind<EntityKind.Object>>>(query: Query<Person & OfKind<EntityKind.Object>>) => QueryResult<Person & OfKind<EntityKind.Object>> (+1 overload)
    query
    (
    const people: Query<Person & OfKind<EntityKind.Object>>
    people
    ).
    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
    ();
    var console: Console

    The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

    The module exports two specific components:

    • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
    • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

    Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

    Example using the global console:

    console.log('hello world');
    // Prints: hello world, to stdout
    console.log('hello %s', 'world');
    // Prints: hello world, to stdout
    console.error(new Error('Whoops, something bad happened'));
    // Prints error message and stack trace to stderr:
    // Error: Whoops, something bad happened
    // at [eval]:5:15
    // at Script.runInThisContext (node:vm:132:18)
    // at Object.runInThisContext (node:vm:309:38)
    // at node:internal/process/execution:77:19
    // at [eval]-wrapper:6:22
    // at evalScript (node:internal/process/execution:76:60)
    // at node:internal/main/eval_string:23:3
    const name = 'Will Robinson';
    console.warn(`Danger ${name}! Danger!`);
    // Prints: Danger Will Robinson! Danger!, to stderr

    Example using the Console class:

    const out = getStreamSomehow();
    const err = getStreamSomehow();
    const myConsole = new console.Console(out, err);
    myConsole.log('hello world');
    // Prints: hello world, to out
    myConsole.log('hello %s', 'world');
    // Prints: hello world, to out
    myConsole.error(new Error('Whoops, something bad happened'));
    // Prints: [Error: Whoops, something bad happened], to err
    const name = 'Will Robinson';
    myConsole.warn(`Danger ${name}! Danger!`);
    // Prints: Danger Will Robinson! Danger!, to err

    @see ― source

    console
    .
    Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

    Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

    const count = 5;
    console.log('count: %d', count);
    // Prints: count: 5, to stdout
    console.log('count:', count);
    // Prints: count: 5, to stdout

    See util.format() for more information.

    @since ― v0.1.100

    log
    (
    const everyone: (Person & OfKind<EntityKind.Object>)[]
    everyone
    .
    Array<Person & OfKind<EntityKind.Object>>.map<string>(callbackfn: (value: Person & OfKind<EntityKind.Object>, index: number, array: (Person & OfKind<EntityKind.Object>)[]) => string, thisArg?: any): string[]

    Calls a defined callback function on each element of an array, and returns an array that contains the results.

    @param ― callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.

    @param ― thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.

    map
    ((
    person: Person & OfKind<EntityKind.Object>
    person
    ) =>
    person: Person & OfKind<EntityKind.Object>
    person
    .
    name: string
    name
    ));
  3. Search text. Filter.text matches objects whose text contains the words, whatever their type. The space indexes text as objects are written.

    /** Every record whose text contains `text`, whatever its type. */
    export const
    const search: (text: string) => Query.Query<any>

    Every record whose text contains text, whatever its type.

    search
    = (
    text: string
    text
    : string) =>
    import Query
    Query
    .
    const select: <Filter.Any>(filter: Filter.Any) => Query.Query<any>

    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 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
    (
    text: string
    text
    , {
    type?: "full-text" | "vector" | undefined
    type
    : 'full-text' }));
    const
    const matches: any[]
    matches
    = await
    const db: Database.Database
    db
    .
    Database.query: Database.QueryFn
    <Query<any>>(query: Query<any>) => QueryResult<any> (+1 overload)
    query
    (
    function search(text: string): Query<any>

    Every record whose text contains text, whatever its type.

    search
    ('Northwind')).
    QueryResult<any>.run(opts?: RunOptions): Promise<any[]>

    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
    ();
  4. Follow references backwards. referencedBy steps from the selected organization to the people whose employer points at it.

    /** The people whose `employer` points at `organization`. */
    export const
    const employeesOf: (organization: Organization) => Query.Query<Person & OfKind<EntityKind.Object>>

    The people whose employer points at organization.

    employeesOf
    = (
    organization: Organization
    organization
    :
    class Organization
    Organization
    ) =>
    import Query
    Query
    .
    const select: <Filter.Any>(filter: Filter.Any) => Query.Query<any>

    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 id: (...ids: EntityId[]) => Filter.Any

    Filter by EntityId.

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

    id
    (
    organization: Organization
    organization
    .
    OfKind<EntityKind.Object>.id: string
    id
    )).
    Query<any>.referencedBy<typeof Person>(target: URI | typeof Person, key: RefPropKey<Person & OfKind<EntityKind.Object>>): Query.Query<Person & OfKind<EntityKind.Object>> (+2 overloads)

    Find objects referencing this object.

    @param ― target - Schema of the referencing object. If not provided, matches any type.

    @param ― key - Property path inside the referencing object that is a reference. If not provided, matches any property.

    @returns ― Query for the referencing objects.

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

    referencedBy
    (
    class Person
    Person
    , 'employer');
    const
    const staff: (Person & OfKind<EntityKind.Object>)[]
    staff
    = await
    const db: Database.Database
    db
    .
    Database.query: Database.QueryFn
    <Query<Person & OfKind<EntityKind.Object>>>(query: Query<Person & OfKind<EntityKind.Object>>) => QueryResult<Person & OfKind<EntityKind.Object>> (+1 overload)
    query
    (
    function employeesOf(organization: Organization): Query<Person & OfKind<EntityKind.Object>>

    The people whose employer points at organization.

    employeesOf
    (
    const northwind: BaseObj & Organization & OfKind<EntityKind.Object>
    northwind
    )).
    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
    ();
  5. Keep a query live. subscribe calls back with the current results each time they change, and returns a function that stops it.

    const
    const unsubscribe: CleanupFn
    unsubscribe
    =
    const db: Database.Database
    db
    .
    Database.query: Database.QueryFn
    <Query<Person & OfKind<EntityKind.Object>>>(query: Query<Person & OfKind<EntityKind.Object>>) => QueryResult<Person & OfKind<EntityKind.Object>> (+1 overload)
    query
    (
    const people: Query<Person & OfKind<EntityKind.Object>>
    people
    ).
    QueryResult<Person & OfKind<EntityKind.Object>>.subscribe(callback?: ((query: QueryResult<Person & OfKind<EntityKind.Object>>) => void) | undefined, opts?: SubscriptionOptions): CleanupFn

    Subscribes to changes in query results.

    @performance ― O(1) registration; the first subscriber starts the live query, whose updates cost an O(n) recompute.

    subscribe
    (({
    results: (Person & OfKind<EntityKind.Object>)[]

    Currently available results.

    results
    }) => {
    var console: Console

    The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

    The module exports two specific components:

    • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
    • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

    Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

    Example using the global console:

    console.log('hello world');
    // Prints: hello world, to stdout
    console.log('hello %s', 'world');
    // Prints: hello world, to stdout
    console.error(new Error('Whoops, something bad happened'));
    // Prints error message and stack trace to stderr:
    // Error: Whoops, something bad happened
    // at [eval]:5:15
    // at Script.runInThisContext (node:vm:132:18)
    // at Object.runInThisContext (node:vm:309:38)
    // at node:internal/process/execution:77:19
    // at [eval]-wrapper:6:22
    // at evalScript (node:internal/process/execution:76:60)
    // at node:internal/main/eval_string:23:3
    const name = 'Will Robinson';
    console.warn(`Danger ${name}! Danger!`);
    // Prints: Danger Will Robinson! Danger!, to stderr

    Example using the Console class:

    const out = getStreamSomehow();
    const err = getStreamSomehow();
    const myConsole = new console.Console(out, err);
    myConsole.log('hello world');
    // Prints: hello world, to out
    myConsole.log('hello %s', 'world');
    // Prints: hello world, to out
    myConsole.error(new Error('Whoops, something bad happened'));
    // Prints: [Error: Whoops, something bad happened], to err
    const name = 'Will Robinson';
    myConsole.warn(`Danger ${name}! Danger!`);
    // Prints: Danger Will Robinson! Danger!, to err

    @see ― source

    console
    .
    Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

    Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

    const count = 5;
    console.log('count: %d', count);
    // Prints: count: 5, to stdout
    console.log('count:', count);
    // Prints: count: 5, to stdout

    See util.format() for more information.

    @since ― v0.1.100

    log
    (`${
    results: (Person & OfKind<EntityKind.Object>)[]

    Currently available results.

    results
    .
    Array<Person & OfKind<EntityKind.Object>>.length: number

    Gets or sets the length of the array. This is a number one higher than the highest index in the array.

    length
    } people`);
    });
    function addPerson(db: Database.Database, { employer, ...props }: {
    name: string;
    email?: string;
    employer?: Organization;
    }): BaseObj & Person & OfKind<EntityKind.Object>
    addPerson
    (
    const db: Database.Database
    db
    , {
    name: string
    name
    : 'Grace Hopper' });
    const unsubscribe: () => void
    unsubscribe
    ();

    The callback runs again for the person added after the subscription, before addPerson returns.

Type in the search box to search every record. The table button shows the records of the chosen type with one column per field. Each list is a live query, so an edit in the form shows up in the list as you save it.

You can select records by type, sort them, search their text, follow references backwards, and keep a query running as the results change.

Sharing a space: replicate the app’s space to a second peer.