TinyBase

setMetricDefinition

The setMetricDefinition method lets you set the definition of a Metric.

setMetricDefinition(
  metricId: string,
  tableId: string,
  aggregate?: Aggregate | "sum" | "avg" | "min" | "max",
  getNumber?: string | (getCell: GetCell, rowId: string) => number,
  aggregateAdd?: AggregateAdd,
  aggregateRemove?: AggregateRemove,
  aggregateReplace?: AggregateReplace,
): Metrics
TypeDescription
metricIdstring

The Id of the Metric to define.

tableIdstring

The Id of the Table the Metric will be calculated from.

aggregate?Aggregate | "sum" | "avg" | "min" | "max"

Either a string representing one of a set of common aggregation techniques ('sum', 'avg', 'min', or 'max'), or a function that aggregates numeric values from each Row to create the Metric's overall value. Defaults to 'sum'.

getNumber?string | (getCell: GetCell, rowId: string) => number

Either the Id of a Cell containing, or a function that produces, the numeric value that will be aggregated in the way specified by the aggregate parameter. Defaults to a function that returns 1 (meaning that if the aggregate and getNumber parameters are both omitted, the Metric will simply be a count of the Row objects in the Table).

aggregateAdd?AggregateAdd

A function that can be used to optimize a custom Aggregate by providing a shortcut for when a single value is added to the input values - for example, when a Row is added to the Table.

aggregateRemove?AggregateRemove

A function that can be used to optimize a custom Aggregate by providing a shortcut for when a single value is removed from the input values - for example ,when a Row is removed from the Table.

aggregateReplace?AggregateReplace

A function that can be used to optimize a custom Aggregate by providing a shortcut for when a single value in the input values is replaced with another - for example, when a Row is updated.

returnsMetrics

A reference to the Metrics object.

Every Metric definition is identified by a unique Id, and if you re-use an existing Id with this method, the previous definition is overwritten.

A Metric is an aggregation of numeric values produced from each Row within a single Table. Therefore the definition must specify the Table (by its Id) to be aggregated.

Without the third aggregate parameter, the Metric will simply be a count of the number of Row objects in the Table. But often you will specify a more interesting aggregate - such as the four predefined aggregates, 'sum', 'avg', 'min', and 'max' - or a custom function that produces your own aggregation of an array of numbers.

The fourth getNumber parameter specifies which Cell in each Row contains the numerical values to be used in the aggregation. Alternatively, a custom function can be provided that produces your own numeric value from the local Row as a whole.

The final three parameters, aggregateAdd, aggregateRemove, aggregateReplace need only be provided when you are using your own custom aggregate function. These give you the opportunity to reduce your custom function's algorithmic complexity by providing shortcuts that can nudge an aggregation result when a single value is added, removed, or replaced in the input values.

Examples

This example creates a Store, creates a Metrics object, and defines a simple Metric to count the Row objects in the Table.

const store = createStore().setTable('species', {
  dog: {price: 5},
  cat: {price: 4},
  worm: {price: 1},
});

const metrics = createMetrics(store);
metrics.setMetricDefinition('speciesCount', 'species');

console.log(metrics.getMetric('speciesCount'));
// -> 3

This example creates a Store, creates a Metrics object, and defines a standard Metric to get the highest value of each price Cell in the Row objects in the Table.

const store = createStore().setTable('species', {
  dog: {price: 5},
  cat: {price: 4},
  worm: {price: 1},
});

const metrics = createMetrics(store);
metrics.setMetricDefinition('highestPrice', 'species', 'max', 'price');

console.log(metrics.getMetric('highestPrice'));
// -> 5

This example creates a Store, creates a Metrics object, and defines a custom Metric to get the lowest value of each price Cell, greater than 2.

const store = createStore().setTable('species', {
  dog: {price: 5},
  cat: {price: 4},
  worm: {price: 1},
});

const metrics = createMetrics(store);
metrics.setMetricDefinition(
  'lowestPriceOver2',
  'species',
  (numbers) => Math.min(...numbers.filter((number) => number > 2)),
  'price',
);

console.log(metrics.getMetric('lowestPriceOver2'));
// -> 4

This example also creates a Store, creates a Metrics object, and defines a custom Metric to get the lowest value of each price Cell, greater than 2. However, it also reduces algorithmic complexity with two shortcut functions.

const store = createStore().setTable('species', {
  dog: {price: 5},
  cat: {price: 4},
  worm: {price: 1},
});

const metrics = createMetrics(store);
metrics.setMetricDefinition(
  'lowestPriceOver2',
  'species',
  (numbers) => Math.min(...numbers.filter((number) => number > 2)),
  'price',
  (metric, add) => (add > 2 ? Math.min(metric, add) : metric),
  (metric, remove) => (remove == metric ? undefined : metric),
  (metric, add, remove) =>
    remove == metric
      ? undefined
      : add > 2
      ? Math.min(metric, add)
      : metric,
);

console.log(metrics.getMetric('lowestPriceOver2'));
// -> 4
store.setRow('species', 'fish', {price: 3});
console.log(metrics.getMetric('lowestPriceOver2'));
// -> 3

This example creates a Store, creates a Metrics object, and defines a custom Metric to get the average value of a discounted price.

const store = createStore().setTable('species', {
  dog: {price: 5, discount: 0.3},
  cat: {price: 4, discount: 0.2},
  worm: {price: 1, discount: 0.2},
});

const metrics = createMetrics(store);
metrics.setMetricDefinition(
  'averageDiscountedPrice',
  'species',
  'avg',
  (getCell) => getCell('price') * (1 - getCell('discount')),
);

console.log(metrics.getMetric('averageDiscountedPrice'));
// -> 2.5