TinyBase logoTinyBase

An Intro To Queries

This guide describes how the queries module gives you the ability to create queries against Tables in the Store - such as selecting specific Row and Cell combinations from each Table, or performing powerful features like grouping and aggregation.

The main entry point to using the queries module is the createQueries function, which returns a new Queries object. That object in turn has methods that let you create new query definitions, access their results directly, and register listeners for when those results change.

The Queries module provides a generalized query concept for Store data. If you just want to create and track metrics, indexes, or relationships between rows, you may prefer to use the dedicated Metrics, Indexes, and Relationships objects, which have simpler APIs.

The Basics

Here's a simple example to show a Queries object in action. The pets Table has three Row objects, each with two Cells. We create a query definition called dogColors which selects just one of those, and filters the Rows based on the value in the other:

import {createQueries, createStore} from 'tinybase';

const store = createStore().setTable('pets', {
  fido: {species: 'dog', color: 'brown'},
  felix: {species: 'cat', color: 'black'},
  cujo: {species: 'dog', color: 'black'},
});

const queries = createQueries(store);
queries.setQueryDefinition('dogColors', 'pets', ({select, where}) => {
  select('color');
  where('species', 'dog');
});

console.log(queries.getResultTable('dogColors'));
// -> {fido: {color: 'brown'}, cujo: {color: 'black'}}

The key to understanding how the Queries API works is in the setQueryDefinition line above. You provide a function which will be called with a selection of 'keyword' functions that you can use to define the query. These include select, join, where, group, and having and are described in the TinyQL guide.

Note that, for getting data out, the Queries object has methods analogous to those in the Store object, prefixed with the word 'Result':

The same conventions apply for registering listeners with the Queries object, as described in the following section.

Queries Reactivity

As with Metrics, Indexes, and Relationships, Queries objects take care of tracking changes that will affect the query results. The familiar paradigm is used to let you add a listener to the Queries object. The listener fires when there's a change to any of the resulting data:

const listenerId = queries.addResultTableListener('dogColors', () => {
  console.log(queries.getResultTable('dogColors'));
});
store.setCell('pets', 'cujo', 'species', 'wolf');
// -> {fido: {color: 'brown'}}

Hopefully the pattern of the method naming is now familiar:

You can set multiple query definitions on each Queries object. However, a given Store can only have one Queries object associated with it. If you call this function twice on the same Store, your second call will return a reference to the Queries object created by the first.

Let's find out how to create different types of queries in the TinyQL guide.