Since we open-sourced Cube in 2019, we’ve added quite a few new features, such as our new SQL API, and integrations, such as our recently-announced support for streaming databases. However, we haven’t changed our core data modeling layer—until now.

Today, we’re announcing a new feature in Cube’s data model: views.

Designed to sit on top of the data graph of cubes, views create a façade of your whole data model with which data consumers can interact. They’re the place to define metrics, manage governance and data access, and control ambiguous join paths.

You can watch the recording of our webinar with an in-depth conversation about views.

Why views? Why now?

As the headless BI platform, Cube helps define and maintain metrics definitions. The fundamental constraint is that metrics should make sense for every downstream application (solved by Cube's SQL API) and every business user at the same time. They should represent substantial entities in a user's business domain and not be obscured by any tool in the data stack. However, we have to admit there's an open debate whether metrics should only describe tangible, real-world entities like users or orders or they're also allowed to reflect more ephemeral concepts like sales funnel, recurring revenue, or storage quota usage.

We're introducing views so Cube's users are well-equipped to build fully semantic layers, i.e., expose metrics that make sense in the business domain at all times and don't include anything obscuring or unnecessary. Using an analogy from software engineering, views allow to define the "public API" on the surface of your semantic layer.

Views diagram

Over the past years, we’ve accumulated a lot of feedback across many use cases that has boiled down to these three questions:

  1. How should single-measure metrics be defined?
  2. How should you manage the visibility of cubes to, e.g., restrict access for specific data consumers?
  3. How can you control the join path within the data graph?

We’ve designed views to tackle these and many other use cases. Now, let’s take an in-depth look at them. (It's worth noting that, if you're familiar with Looker and LookML, you can find some similarities between views and Looker's explores.)

1. Defining metrics with views

Views with a single measure can be used to define metrics.

Here’s a simple example that demonstrates the relationship between a view and its underlying cubes. To define a metric with a view, pick a measure from your data model together with the dimensions:

Views explained diagram

You can use the includes property to bulk add measures or dimensions to a view.

JS
YAML
view(`ActiveUsers`, {
description: `14 days rolling count of active users`,
includes: [
// Measure
Users.rollingCount,
// Dimensions
Users.isPaying,
Users.signupDate,
Company.name
]
});

You can query these metrics views via REST or SQL API the same way you query cubes. In Cube’s SQL API, views are exposed as tables in which measures and dimensions are columns.

SELECT
margin,
categoryName
FROM OrdersMargin
GROUP BY 2

Curious about YAML? We have seen a lot of requests to support YAML for data modeling, and we’re planning a release later this year. Please stay tuned for updates and reach out to us if you’d like to sign up for early access to YAML support.

2. Managing visibility and governance

Views can help you manage visibility of your data model through the shown property. Some data may be available only to specific roles within an organization or to specific customers.

In the example below, we’re making the ARR view only visible to users with finance permissions:

JS
YAML
view(`ARR`, {
description: `Annual Recurring Revenue`,
shown: COMPILE_CONTEXT.permissions.finance,
includes: [
Revenue.arr,
Revenue.date,
Customers.plan
]
});

You can also use the shown property to manage visibility of the specific measures and dimensions based on the users’ permissions.

3. Controlling join paths

Sometimes your data model may feature more than one way to join two cubes. The schema below illustrates a simplified example of that case, where the Countries cube can be accessed from Orders either directly or via the Users cube.

The join path is a part of your semantic model since it affects the meaning of calculations. In the example below, we can look either at an order’s warehouse country or the country of the user who placed the order.

Join in Cube data model

Use views to control the join path. In the example below, we are creating two dimensions with the same Countries cube and name dimension, but with different semantic meaning because of the join path.

JS
YAML
view(`CompletedOrders`, {
description: 'Count of orders',
includes: [
Orders.count
],
dimensions: {
orderWarehouseCountry: {
sql: `${Orders.Countries.name}`,
type: `string`
},
userCountry: {
sql: `${Orders.Users.Countries.name}`,
type: `string`
}
}
});

Available now

Views are available in both Cube Core and Cube Cloud starting from version 0.31 (see docs for details). However, they’re optional: if you don’t need them, don’t use them.

Views can be very helpful to develop and maintain large data models or provide governance for many data consumers, but they may be overkill for smaller projects.

In addition to the three cases detailed here, we believe views will enable many additional opportunities, so we’re eager to see how you use them. Please get in touch with your feedback, questions, and examples.