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
getResultTablemethod is theQueriesequivalent of thegetTablemethod. - The
getResultRowIdsmethod is theQueriesequivalent of thegetRowIdsmethod. - The
getResultSortedRowIdsmethod is theQueriesequivalent of thegetSortedRowIdsmethod. - The
getResultRowmethod is theQueriesequivalent of thegetRowmethod. - The
getResultCellIdsmethod is theQueriesequivalent of thegetCellIdsmethod. - The
getResultCellmethod is theQueriesequivalent of thegetCellmethod.
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:
- The
addResultTableListenermethod is theQueriesequivalent of theaddTableListenermethod. - The
addResultRowIdsListenermethod is theQueriesequivalent of theaddRowIdsListenermethod. - The
addResultSortedRowIdsListenermethod is theQueriesequivalent of theaddSortedRowIdsListenermethod. - The
addResultRowListenermethod is theQueriesequivalent of theaddRowListenermethod. - The
addResultCellIdsListenermethod is theQueriesequivalent of theaddCellIdsListenermethod. - The
addResultCellListenermethod is theQueriesequivalent of theaddCellListenermethod.
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.