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 queryconst $ = 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 queryawait $.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 secondssetTimeout(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 queryawait db.users.query(($) => $.field("name").eq("Sasha"));//=> Doc<User>[]
// Array of queriesawait 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
- field is equal to a value$.field(...).not
- field is not equal to a value$.field(...).lt
- field is less than a value$.field(...).lte
- field is less or equal to a value$.field(...).gt
- field is greater than a value$.field(...).gte
- field is greater or equal to a value$.field(...).in
- field is in an array of values$.field(...).notIn
- field is not in an array of values$.field(...).contains
- field array contains a value$.field(...).containsAny
- field array contains any of the values$.field(...).order
- order the query by the field
$.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:
$.startAt
- start the range at a value$.startAfter
- start the range after a value$.endAt
- end the range at a value$.endBefore
- end the range before a value
$.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