An Intro To Indexes
This guide describes how the indexes
module gives you the ability to create and track indexes based on the data in Store
objects, and which allow you to look up and display filtered data quickly.
The main entry point to using the indexes
module is the createIndexes
function, which returns a new Indexes
object. That object in turn has methods that let you create new Index
definitions, access the content of those Indexes
directly, and register listeners for when they change.
The Basics
An Index
comprises a map of Slice
objects, keyed by Id
. The Ids
in a Slice
represent Row
objects from a Table
that all have a derived string value in common, as described by the setIndexDefinition
method. Those values are used as the key for each Slice
in the overall Index
object.
This might be simpler to understand with an example: if a Table
contains pets, each with a species, then an Index
could be configured to contain the Ids
of each Row
, grouped into a Slice
for each distinct species. In other words, this Table
:
{ // Store
pets: {
fido: {species: 'dog'},
felix: {species: 'cat'},
cujo: {species: 'dog'},
},
}
would conceptually become this Index
:
{ // Indexes
bySpecies: {
dog: ['fido', 'cujo'],
cat: ['felix'],
},
}
This is for illustrative purposes: note that this resulting Index
structure is never an object literal like this: you would instead use the getSliceIds
method and the getSliceRowIds
method to iterate through the it.
Here's a simple example to show such an Index
in action. The pets
Table
has three Row
objects, each with a string species
Cell
. We create an Index
definition called bySpecies
which groups them:
import {createIndexes, createStore} from 'tinybase';
const store = createStore().setTable('pets', {
fido: {species: 'dog'},
felix: {species: 'cat'},
cujo: {species: 'dog'},
});
const indexes = createIndexes(store);
indexes.setIndexDefinition(
'bySpecies', // indexId
'pets', // tableId to index
'species', // cellId to index on
);
console.log(indexes.getSliceIds('bySpecies'));
// -> ['dog', 'cat']
console.log(indexes.getSliceRowIds('bySpecies', 'dog'));
// -> ['fido', 'cujo']
Index
Reactivity
As with the Metrics
object, magic happens when the underlying data changes. The Indexes
object efficiently takes care of tracking changes that will affect the Index
or the Slice
arrays within it. A similar paradigm to that used on the Store
is used to let you add a listener to the Indexes
object. The listener fires when there's a change to the Slice
Ids
or a Slice
's content:
indexes.addSliceIdsListener('bySpecies', () => {
console.log(indexes.getSliceIds('bySpecies'));
});
store.setRow('pets', 'lowly', {species: 'worm'});
// -> ['dog', 'cat', 'worm']
indexes.addSliceRowIdsListener('bySpecies', 'worm', () => {
console.log(indexes.getSliceRowIds('bySpecies', 'worm'));
});
store.setRow('pets', 'smaug', {species: 'worm'});
// -> ['lowly', 'smaug']
You can set multiple Index
definitions on each Indexes
object. However, a given Store
can only have one Indexes
object associated with it. So, as with the Metrics
object, if you call this function twice on the same Store
, your second call will return a reference to the Indexes
object created by the first.
Let's next find out how to include Indexes
in a user interface in the Building A UI With Indexes guide.