Dynamic Data Sources & Schemas for Embedded Analytics
This feature is under active development and will be coming soon!
Introduction
When implementing embedded analytics, you may have customers with their own separate databases (or schemas). In this case, you'll want to configure your embedded dashboard to dynamically connect to the appropriate database based on which user is viewing it.
This post explains how to do that using our Dynamic Data Sources mechanism.
Use Case: Dynamic Data Source
1. Connect databases
First, make sure you connect all databases of your customers to Holistics.
The data source name will be used to identify which database to connect to at later steps, so you should use a unique and meaningful name for each data source.
2. Create a data_source
variable in your AML codes
Go to the Development tab, create a new file embedded_variables.aml
and add the following code:
const client_data_source = create_slot<String>({
path: 'H.embed.attributes.data_source'
})
Tip: you can name the file anything you want, as long as it ends with .aml
.
3. Modify the embedded dashboard's dataset code
Modify the dataset code that powers the embedded dashboard to use this data_source
variable:
Dataset dynamic_client_dataset {
label: 'Dynamic Client Dataset'
data_source_name: if (client_data_source) {
client_data_source
} else {
'dev_datasource'
}
models: [ orders ]
relationships: [ ]
}
4. Pass data source name in the backend
When generating the embedded payload on your backend app, you can calculate and pass in the appropriate data source depending on your currently logged-in user.
// Embedded payload
embedded_payload = {
permissions: {},
attributes: {
data_source: 'your_data_source_name'
}
}
Use case: Dynamic Schema
1. Create a schema
variable in your AML codes
const client_schema = create_slot<String>({ path: 'H.embed.attributes.schema' })
2. Modify the embedded dashboard's data models
- For TableModel
Model dynamic_model {
type: 'table'
data_source_name: 'my_wh'
table_name: '${client_schema}.cities'
}
- For QueryModel
Model dynamic_model {
type: 'query'
data_source_name: 'my_wh'
query: @sql
select *
from ${client_schema}.cities
;;
models: []
}
3. Pass schema name in the backend
// Embedded payload
embedded_payload = {
permissions: {},
attributes: {
schema: 'your_schema_name'
}
}
How it works
The dynamic feature works through a simple two-step process:
- First, it creates a variable with a predefined
path
that acts as a placeholder - Then, when you send a JSON payload to Holistics, the system locates the variable using this
path
and dynamically replaces it with the actual value from your payload
This allows you to flexibly change data sources/schemas at runtime based on the values you provide.
Supported Paths
H.embed.attributes.*
The H.embed.attributes.*
path allows you to define custom attributes that can be dynamically set through the embedded payload. The *
represents any valid attribute name of your choice.
Here's an example demonstrating how to use custom attributes for 2 data sources:
First, you create 2 variables:
const client_a_data_source = create_slot<String>({
path: 'H.embed.attributes.client_a_data_source'
})
const client_b_data_source = create_slot<String>({
path: 'H.embed.attributes.client_b_data_source'
})
Then, you pass those values in the embedded payload:
embedded_payload = {
permissions: {},
attributes: {
client_a_data_source: 'client_a_data_source',
client_b_data_source: 'client_b_data_source'
}
}
H.embed.is_embedded
This is a built-in variable that will be true
if the dashboard is viewed in the embedded mode, and false
if it's not. This is useful when you want to test this dashboard in your Development environment.
Example:
const is_embedded = create_slot<Boolean>({ path: 'H.embed.is_embedded' })
const client_data_source = create_slot<String>({ path: 'H.embed.attributes.data_source' })
const data_source_name = if (is_embedded) {
client_data_source
} else {
'dev_datasource'
}
Supported Data Types
Currently, you can pass these JSON data types in the embedded payload:
JSON Type | Holistics Type |
---|---|
string | String |
boolean | Boolean |
number | Number |
array | 🛠️ To be supported soon |
Advanced example
const dynamic_data_source = create_slot<String>({
path: 'H.embed.attributes.data_source'
})
const dynamic_schema = create_slot<String>({
path: 'H.embed.attributes.schema'
})
const is_embedded = create_slot<String>({ path: 'H.embed.is_embedded' })
// Define a custom type to group data source and schema into a single object for easier access
Type DynamicSource {
data_source: Slot<String>
schema: Slot<String>
}
DynamicSource dynamic_source {
data_source: if (is_embedded) { dynamic_data_source } else { 'dev_datasource' }
schema: if (is_embedded) { dynamic_schema } else { 'dev_schema' }
}
// In a Dataset
Dataset dynamic_dataset {
data_source_name: dynamic_source.data_source // dynamic data source
// ...omit for brevity
}
// In a TableModel
Model dynamic_model {
type: 'table'
data_source_name: dynamic_source.data_source // dynamic data source
table_name: '${dynamic_source.schema}.orders' // dynamic schema
// ...omit for brevity
}