Materialised views

Combine columns from several entities into one table, with a row per record, and put it on a dashboard without writing queries.

Last updated

A materialised view is a saved table definition. You pick one entity to supply the rows, such as your users or customers, then add columns that pull in data from other entities: whether each row has a matching record, or a field from the latest one. Put the view on a dashboard as a widget and your team reads it as a table.

Note: Anythink calculates a materialised view each time it's opened. Nothing is stored, so there's no refresh to schedule and the table is always current. For a count, total or trend over time, use a chart instead: see Dashboards and charts.

When to use one#

You want Use
One row per customer, with columns showing whether they have ordered, and the amount of their latest order A materialised view
One number or one line over time A Chart widget
The latest rows of a single entity A List widget

A view fits best when the question is "which of these records have a matching record somewhere else?".

How a view is built#

Part What it does
Base entity The entity that supplies one row per record. Leave it empty for a totals only view, which shows just the TOTAL row
Base row filter Conditions that limit which base records appear
Columns The data shown beside each row
Timeframe Limits the records that columns look at: all time, 24 hours, 7, 30, 90 or 365 days, or a custom range. Offset (days back) shifts the window
Compare vs prior Measures each column's total against an earlier window and shows the percentage change in the column header. The window is the same length as the timeframe unless you set Compare previous (days)
Row limit, sort How many rows per page, and which base field they're sorted by

Columns#

Each column has a Label, a Source and a Display.

Source says where the column's data comes from:

Source Reads from
entity Another entity. You choose the Entity and Match on, the field on that entity that holds the base record's id
base_field A field on the base row itself
payments, subscriptions, subscription_events, offer_redemptions AnythinkPay, if your project uses it: see How payments and subscriptions work

Display says how each cell looks:

Display Cell shows
exists A marker (x unless you set another one) when the row has a matching record, otherwise empty
count 1 when the row has a matching record, 0 when it doesn't
value The value of Value field from the matching record. Order picks the latest or first record by creation date

A column can have its own filters and, on an entity source, a since_days limit, so one view can hold both "has any order" and "has a paid order in the last 30 days".

The TOTAL row#

The TOTAL row sits under the table and counts across the whole project, not just the rows on the current page. For an entity column it's the number of matching records, after the column's filters and the timeframe.

Create a view#

In the Anythink dashboard

  1. Open Dashboard and select the pencil (Customize dashboard).
  2. Select Add widget and choose Materialised view. The design window opens.
  3. Enter a Name and, if you like, a Description.
  4. Under Show one row per, pick the base entity, or leave it as Totals only.
  5. Optionally open Base row filter and add conditions.
  6. Open Timeframe & compare to set the window and, if you want it, Compare vs prior.
  7. Under Columns, select Add column. Set the Source, the Entity and Match on field for an entity source, the Display, and the Value field for a value column. Add a column-level filter if you need one.
  8. Check the Preview, then save. The widget is added to the dashboard. Select Save on the dashboard.

To change a view, edit its widget in customise mode.

With the CLI

Views are created and edited in the Anythink dashboard. Use the steps above.

With an AI assistant (MCP)

Views are created and edited in the Anythink dashboard. Your assistant can walk you through the steps above.

Show a view on a dashboard#

A view appears on a dashboard as a Materialised view widget. It shows the columns as a table with the TOTAL row pinned under it and pages through the rows. Percentage changes from Compare vs prior show in the column headers.

In the Anythink dashboard

Create the view from Add widget as above, or edit the widget later in customise mode. The table widget is a view of the data only: to change the definition, open the widget's editor.

With the CLI

Put an existing view on a dashboard with a materialised_view widget whose config_json holds the view's id:

bash
anythink fetch /dashboards --method POST --body '{
  "name": "Customers",
  "widgets": [
    {"type": "materialised_view", "title": "Customer orders", "config_json": "{\"viewId\":6}", "sort_order": 0}
  ]
}'

Add the widget to an existing dashboard by sending the whole widget list on PUT /dashboards/<id>: see Dashboards and charts.

With an AI assistant (MCP)

Add the Customer orders materialised view to my Customers dashboard.

Positioning the widget is easier in the Anythink dashboard.

Permissions#

Materialised views use the anythink_entities permission, the same one that guards entities and charts.

Action Permission
List and read views, and read their data anythink_entities:read
Create a view anythink_entities:create
Change a view anythink_entities:update
Delete a view anythink_entities:delete

Showing a view on a dashboard also needs anythink_dashboards: see Dashboards and charts. For a custom role, tick the permissions on the role: see Roles and permissions. A missing permission shows as a 403.

Limits#

  • Calculated live. There's no stored result, refresh schedule or export. A wide timeframe over a large entity takes longer to open.
  • One row per base record. Rows are paged: 100 per page by default, up to 1,000.
  • count is a match flag. It shows 1 or 0 for each row, not the number of matching records. The TOTAL row holds the project-wide count.
  • Sort by a base field. The sort applies to a field on the base entity, not to one of the view's columns.
  • One join field per column. An entity column joins on a single field of the other entity that holds the base record's id.
  • Value columns need a value_field. A column that can't be calculated reports why in diagnostics, and the other columns still load.
  • AnythinkPay sources need AnythinkPay set up in the project.
  • Widget editing is dashboard-only. The CLI and your assistant create views and dashboards, while placing and sizing the widget is done in the Anythink dashboard.

Next steps#