Skip to content

query

To query a collection, use the query method on Collection:

It accepts a function as the argument, where you define the query.

The method returns an array of Doc instances:

await db.users.query(($) => [
$.field("name").eq("Sasha"),
$.field("birthday").gte(new Date(2000, 1, 1)),
]);
//=> Doc<User>[]

Builder mode

The query also allows you to use the builder mode, where you accumulate the query operations and then call run to execute them:

// Start building the query
const $ = db.users.query.build();
$.field("name").eq("Sasha");
// ...Do something in between, including async operations
$.field("birthday").gte(new Date(2000, 1, 1));
// Run the query
await $.run();
// Doc<User>[]

Subscription

Instead of awaiting the promise returned from query, you can call on on it to subscribe to the document updates:

db.users
.query(($) => [
$.field("name").eq("Sasha"),
$.field("birthday").gte(new Date(2000, 1, 1)),
])
.on((users) => {
// Doc<User>[]
});

To catch errors, use catch after calling on:

db.users
.query(($) => [
$.field("name").eq("Sasha"),
$.field("birthday").gte(new Date(2000, 1, 1)),
])
.on((users) => {
// ...
});
.catch((error) => {
//=> PERMISSION_DENIED: Missing or insufficient permissions
});

To stop listening to the updates, call the off function returned from the method:

const off = db.users
.query(($) => [
$.field("name").eq("Sasha"),
$.field("birthday").gte(new Date(2000, 1, 1)),
])
.on((users) => {
// ...
});
// Unsubscribe after 5 seconds
setTimeout(off, 5000);

You can also subscribe to query in the builder mode:

const $ = db.users.query.build();
$.field("name").eq("Sasha");
$.field("birthday").gte(new Date(2000, 1, 1));
// Subscribe to the query
$.run().on((users) => {
// Doc<User>[]
});

Read more about subscribing to real-time updates

Pagination

To paginate data, use one of the methods provided by the $ helper:

await db.users.query(($) => [
// $.docId - use the id for sorting
$.field($.docId()).order($.startAfter(lastUserId)),
// Every page - 25 documents
$.limit(25),
]);

Use last user id, starting with undefined, to query the page, $.limit to specify the page size.

Aggregation queries

You can use queries to aggregate data in a collection. There are three methods available: count, sum, and average.

count

You can count the documents in a collection by calling the count method:

await db.users
.query(($) => $.field("name").eq("Alexander"))
// Call count method:
.count();
//=> 42

The method returns Promise<number>.

sum

You can sum the document fields in a collection by calling the sum method:

await db.users
.query(($) => $.field("name").eq("Alexander"))
// Call sum method:
.sum("age");
//=> 123

The method returns Promise<number>.

average

You can calculate the average of the document fields in a collection by calling the average method:

await db.users
.query(($) => $.field("name").eq("Alexander"))
// Call average method:
.average("age");
//=> 42

The method returns Promise<number>.

$ helper

The argument function receives $ helper object as the first argument that provides the query API.

$ type is TypesaurusQuery.Helpers.

You can return either a single query, array of queries or falsy value to skip the query and return undefined:

// Single query
await db.users.query(($) => $.field("name").eq("Sasha"));
//=> Doc<User>[]
// Array of queries
await db.users.query(($) => [
$.field("name").eq("Sasha"),
$.field("birthday").gte(new Date(2000, 1, 1)),
]);
//=> Doc<User>[]
// If name is string or null:
await db.users.query(($) => name && $.field("name").eq(name));
//=> undefined | Doc<User>[]

$.field

The $.field allows you to target specific fields in the document. It allows you to query nested fields as well:

await db.users.query(($) =>
// Where profile.name.first is Alexander
$.field("profile", "name", "first").eq("Alexander"),
);

The result of the $.field provides a few methods that define the query:

$.field(...).eq

To query documents where the field is equal to a value, use the eq method:

await db.users.query(($) =>
// Query users named Alexander
$.field("profile", "name", "first").eq("Alexander"),
);

$.field(...).not

To query documents where the field is not equal to a value, use the not method:

await db.users.query(($) =>
// Query users not named Alexander
$.field("profile", "name", "first").not("Alexander"),
);

$.field(...).lt

To query documents where the field is less than a value, use the lt method:

await db.games.query(($) =>
// Query games with rating less than 3
$.field("rating").lt(3),
);

The method only works with numbers and dates.

$.field(...).lte

To query documents where the field is less or equal to a value, use the lte method:

await db.games.query(($) =>
// Query games with rating 3 or less
$.field("rating").lte(3),
);

The method only works with numbers and dates.

$.field(...).gt

To query documents where the field is greater than a value, use the gt method:

await db.games.query(($) =>
// Query games with rating greater than 8
$.field("rating").gt(8),
);

The method only works with numbers and dates.

$.field(...).gte

To query documents where the field is greater or equal to a value, use the gte method:

await db.games.query(($) =>
// Query games with rating 8 or greater
$.field("rating").gte(8),
);

The method only works with numbers and dates.

$.field(...).in

To query documents where the field is in an array of values, use the in method:

await db.games.query(($) =>
// Query games published by Nintendo or Sony
$.field("publisher").in(["Nintendo", "Sony"]),
);

$.field(...).notIn

To query documents where the field is not in an array of values, use the notIn method:

await db.games.query(($) =>
// Query games not published by Nintendo or Sony
$.field("publisher").notIn(["Nintendo", "Sony"]),
);

$.field(...).contains

To query documents where the field array contains a value, use the contains method:

await db.games.query(($) =>
// Query games that has rpg tag
$.field("tags").contains("rpg"),
);

The method only works with arrays.

$.field(...).containsAny

To query documents where the field array contains any of the values, use the containsAny method:

await db.games.query(($) =>
// Query games that has rpg or action tag
$.field("tags").containsAny(["rpg", "action"]),
);

The method only works with arrays.

$.field(...).order

To order the query by the field, use the order method:

await db.games.query(($) =>
// Order games published between 2000 and 2010 by year
$.field("year").order("desc", [$.startAt(2000), $.endAt(2010)]),
);

It accepts the optional direction ("asc" | "desc") and optionally the range of values to order by. You can call the method without any arguments to order by the field in ascending order:

await db.games.query(($) =>
// Order games by year in ascending order
$.field("year").order(),
);

The field helpers that can be used to define the range are:

$.or

To query documents that match any of the queries, use the or method:

await db.users.quer(($) => [
$.field("age").gte(21),
$.or($.field("name").eq("Sasha"), $.field("name").eq("Tati")),
]);

All the rest queries are considered to be joined by the and operator.

$.limit

To limit the number of documents returned by the query, use the limit method:

await db.users.query(($) =>
// Query 10 users
$.limit(10),
);

$.startAt

To start the range at a value, use the startAt method:

await db.games.query(($) =>
// Query games published 2000 or later
$.field("year").order($.startAt(2000)),
);

$.startAfter

To start the range after a value, use the startAfter method:

await db.games.query(($) =>
// Query games published after 2019
$.field("year").order($.startAfter(2019)),
);

$.endAt

To end the range at a value, use the endAt method:

await db.games.query(($) =>
// Query games published 2019 or earlier
$.field("year").order($.endAt(2019)),
);

$.endBefore

To end the range before a value, use the endBefore method:

await db.games.query(($) =>
// Query games published before 2000
$.field("year").order($.endBefore(2000)),
);

$.docId

To use the document id in the query, use the $.docId method:

await db.users.query(($) => [
// Query users after the last user id
$.field($.docId()).order($.startAfter(lastUserId)),
$.limit(25),
]);

It effectively allows you to paginate the query.

Options

as

You can tell Typesaurus that it’s safe to use dates by passing the as option ("server" | "client"):

const [serverUser] = await db.users.query(($) => $.field("name").eq("Sasha"), {
as: "server",
});
serverUser && serverUser.data.createdAt;
//=> Date
const [clientUser] = await db.users.query(($) => $.field("name").eq("Sasha"), {
as: "client",
});
clientUser && clientUser.data.createdAt;
//=> Date | null

By default, Typesaurus uses the "client" option.

The builder mode also accepts the as option:

const $ = db.users.query.build({ as: "server" });
$.field("name").eq("Sasha");
$.field("birthday").gte(new Date(2000, 1, 1));
const [serverUser] = await $.run();
serverUser && serverUser.data.createdAt;
//=> Date

Read more about server dates.