Cube.js:開源儀表板框架的終極指南

Cube.js:開源儀表板框架的終極指南


Cube.js是一個用於構建分析 web 應用程序的開源框架,主要用於構建內部的商業智能工具或將面向客戶的分析添加到現有的應用程序當中。大多數情況下,構建此類應用程序的第一步是分析儀表板。通常從“在管理面板中添加一個分析儀表板”開始,然後就像軟件開發中經常發生的那樣,事情會變得更加複雜。

當開始使用 Cube.js 時,會想要構建一個工具,它起初很簡單,但在功能、複雜性和數據量方面很容易擴展。Cube.js 為未來的分析系統奠定堅實的基礎,無論是獨立的應用程序還是嵌入到現有的分析系統中。

本教程可以視為“Cube.js 101”,它介紹了從數據庫到可視化的第一個儀表板的基本設計步驟。

最終儀表板的現場演示可在此處獲得。完整的源代碼在 GitHub 上。

架構

大多數現代 web 應用程序都是作為單頁面應用程序構建的,前端與後端分離。遵循微服務架構,後端通常也會分成多個服務。

通常,Cube.js 的後端作為服務運行,管理與數據庫的連接,包括查詢隊列、緩存、預聚合等。同時為前端應用程序公開一個 API,用於構建儀表板和其他分析功能。

Cube.js:開源儀表板框架的終極指南


後端

分析從數據產生並駐留在數據庫中開始,如果用戶已經有一個適用於應用程序的數據庫,通常它可以直接用於分析。現代流行的數據庫,如 Postgres 或 MySQL,都可以做簡單的分析工作,這裡的簡單指的是行數少於 10 億的數據量。

另外,MongoDB 也可以,不過需要添加 MongoDB Connector for BI。它允許在 MongoDB 數據之上執行 SQL 代碼。這是免費的,可以從 MongoDB 網站直接下載。需要注意的是,出於性能問題的考慮,直接在生產數據庫上運行分析查詢是不好的做法。所以,即使 Cube.js 可以顯著減少數據庫的工作量,但仍然建議連接到副本。

總而言之,如果使用 Postgres 或 MySQL,只需創建一個副本就可以了。如果您使用 MongoDB,請下載 MongoDB Connector for BI 並創建副本。

如果沒有構建儀表板的任何數據,可以加載示例中的電子商務 Postgres 數據集。

Cube.js:開源儀表板框架的終極指南


數據庫中有數據,就可以開始創建 Cube.js 的後端服務。在終端中運行以下命令:

Cube.js:開源儀表板框架的終極指南


上面的命令安裝 Cube.js CLI,並創建一個新服務,配置為可以與 Postgres 數據庫一起使用。

Cube.js 使用環境變量進行配置,環境變量以 CUBEJS_ 開頭。要配置與數據庫的連接,需要指定數據庫的類型和名稱。在 Cube.js 項目文件夾中,替換.env 的以下內容:

Cube.js:開源儀表板框架的終極指南


Cube.js 數據 Schema

下一步是創建一個Cube.js 數據 Schema。Cube.js 利用數據 Schema 生成 SQL 代碼,該代碼將在數據庫中執行。數據 Schema 不是 SQL 的替代品,它旨在使 SQL 可重用並賦予其結構,同時保留其所有功能。數據 Schema 的基本元素是 measures 和 dimensions。

,

Measure 被稱為定量數據,例如單位銷售數、唯一訪問量、利潤等。

Dimension 被稱為分類數據,例如狀態、性別、產品名稱或時間單位(例如,日、周、月)。

通常,模式文件位於 schema 文件夾中。以下是架構的示例,可用於描述用戶的數據。

Cube.js:開源儀表板框架的終極指南


現在,通過上述 Schema,可以向 Cube.js 後端發送有關用戶數據的查詢。Cube.js 查詢是純 JavaScript 對象。通常情況下,它有一個或多個 measures、dimensions 和 timeDimensions。

如果要回答“用戶在哪裡?”這個問題,可以將以下查詢發送到 Cube.js:

Cube.js:開源儀表板框架的終極指南


Cube.js 將根據 Schema 生成所需的 SQL,執行它並將結果發回。

我們可以創建一個稍微複雜的查詢,添加一個 timeDimensions,看看去年不同城市的比例在每個月是如何變化的。為此,需要添加 signedUp 時間維度,按月分組,並僅包含去年的註冊。

Cube.js:開源儀表板框架的終極指南


Cube.js 還可以根據數據庫的表生成簡單的 Schema,並需要為儀表板生成所需的 Schema,啟動一個供開發的服務器。

Cube.js:開源儀表板框架的終極指南


可以通過在http://localhost:4000打開開發後臺,檢查生成的 Schema 併發送測試的查詢。

前端

通過 Cube.js 的 React 客戶端,可以使用 React 來構建前端和儀表板。也可以使用任何框架或只使用 vanilla JavaScript 來構建 Cube.js 的前端,這個教程將向您展示如何在純 JavaScript 中構建儀表板。我們將使用 React 團隊正式支持的 Create React App 來設置所有內容,它打包了 React 應用程序的所有依賴項,可以輕鬆地開始使用新項目。在終端中運行以下命令:

Cube.js:開源儀表板框架的終極指南


最後一行在端口 3000 上啟動服務器,並通過http://localhost:3000打開 web 瀏覽器。

我們將使用 Reactstrap 來構建我們的 UI,它是 Bootstrap 4 的 React wrapper。用 NPM 來安裝 Reactstrap 和 Bootstrap。Reactstrap 不包括 Bootstrap CSS,所以需要單獨安裝:

Cube.js:開源儀表板框架的終極指南


導入./index.css 之前,導入 src/index.js 文件中的 Bootstrap CSS:

Cube.js:開源儀表板框架的終極指南


現在,我們已準備好使用 Reactstrap 組件。

下一步是安裝 Cube.js 客戶端,這樣可以從服務器和可視化庫中獲取數據並進行顯示。在本教程中,我們將使用 Recharts。Cube.js 是可視化不可知的,這意味著可以使用任何所需的庫。我們還將使用 moment 和 numeral 來很好地格式化日期和數字。

Cube.js:開源儀表板框架的終極指南


這樣,我們搞定了依賴關係。接下來繼續創建我們的第一個圖表,用以下替換 src/App.js 的內容:

import React, { Component } from "react";
import {
BarChart,
Bar,
XAxis,
YAxis,
Tooltip,
ResponsiveContainer
} from "recharts";
import cubejs from "@cubejs-client/core";
import moment from "moment";
import { QueryRenderer } from "@cubejs-client/react";

const cubejsApi = cubejs(process.env.REACT_APP_CUBEJS_TOKEN, {
apiUrl: process.env.REACT_APP_API_URL
});

const dateFormatter = item => moment(item).format("MMM YY");

class App extends Component {
render() {
return (
<queryrenderer> query={{
measures: ["Orders.count"],
timeDimensions: [
{
dimension: "Orders.createdAt",
dateRange: ["2017-01-01", "2018-12-31"],
granularity: "month"
}
]
}}
cubejsApi={cubejsApi}
render={({ resultSet }) => {
if (!resultSet) {
return "Loading...";
}

return (
<responsivecontainer>

<barchart>
<xaxis>
<yaxis>
<tooltip>

/<barchart>
/<responsivecontainer>
);
}}
/>
);
}
}

export default App;
/<queryrenderer>

可以在下面的CodeSandbox中查看此示例。

Cube.js:開源儀表板框架的終極指南


接下來,讓我們更深入地瞭解如何加載數據並繪製圖表。

首先,我們初始化 Cube.js API 客戶端:

Cube.js:開源儀表板框架的終極指南


這裡,我們使用 REACT_APP_CUBEJS_TOKEN 和 REACT_APP_API_URL 這兩個環境變量。如果環境變量以 REACT_APP_ 開頭,Create React App 會自動從.env 文件中加載。Cube.js 後端將在啟動期間打印這些 API token。

Cube.js:開源儀表板框架的終極指南


使用正確的憑據創建.env 文件。

Cube.js:開源儀表板框架的終極指南


接下來,我們使用 QueryRenderer Cube.js React Component 來加載 Orders 數據。

Cube.js:開源儀表板框架的終極指南


QueryRenderer 對 Cube.js 後端執行 API 請求,並根據需要使用render props技術來渲染結果。我們上面已經介紹了查詢格式,想得到最新的格式,這裡是查詢格式的完整參考。

QueryRenderer 的參數 render,是幾個類型的函數 ({error, resultSet, isLoading}) => React.Node。該函數的輸出將由 QueryRenderer 提供。resultSet 是從查詢獲得的數據對象,如果未定義此對象,則表示仍在提取數據中。

resultSet 提供了多種數據操作方法,但在我們的例子中,只需要 chartPivot 方法,它以 Recharts 預期的格式返回數據。

我們將訂單數據繪製成響應式容器內的條形圖。

Cube.js:開源儀表板框架的終極指南


構建儀表板

我們學習瞭如何使用 Cube.js 和 Recharts 構建單個圖表,現​​在可以開始構建整個儀表板。可以找到設計儀表板佈局的一些最佳實踐,通常的做法是將最重要和最高級別的指標放在頂部作為單值圖表(有時稱為KPI),然後列出這些指標的相關細節。

以下是最終儀表板的屏幕截圖,其中 KPI 位於頂部,下面是條形圖和折線圖。

Cube.js:開源儀表板框架的終極指南


首先,讓我們重構圖表,並將公共代碼提取到可重用的組件中。用以下的內容創建一個 src/Chart.js 文件:

Cube.js:開源儀表板框架的終極指南



接下來,讓我們使用此組件來創建儀表板。用以下內容替換 src/App.js:

複製代碼

import React, { Component } from "react";
import { Container, Row, Col } from "reactstrap";
import {
AreaChart,
Area,
XAxis,
YAxis,
Tooltip,
ResponsiveContainer,
Legend,
BarChart,
Bar
} from "recharts";
import moment from "moment";
import numeral from "numeral";
import cubejs from "@cubejs-client/core";
import Chart from "./Chart.js";

const cubejsApi = cubejs(process.env.REACT_APP_CUBEJS_TOKEN, {
apiUrl: process.env.REACT_APP_API_URL
});
const numberFormatter = item => numeral(item).format("0,0");
const dateFormatter = item => moment(item).format("MMM YY");

const renderSingleValue = (resultSet, key) => (

{numberFormatter(resultSet.chartPivot()[0][key])}


);

class App extends Component {
render() {
return (
<container>


<chart> cubejsApi={cubejsApi}
title="Total Users"
query={{ measures: ["Users.count"] }}
render={resultSet => renderSingleValue(resultSet, "Users.count")}
/>


<chart> cubejsApi={cubejsApi}
title="Total Orders"
query={{ measures: ["Orders.count"] }}
render={resultSet => renderSingleValue(resultSet, "Orders.count")}
/>


<chart> cubejsApi={cubejsApi}
title="Shipped Orders"
query={{
measures: ["Orders.count"],
filters: [
{
dimension: "Orders.status",
operator: "equals",
values: ["shipped"]
}
]
}}
render={resultSet => renderSingleValue(resultSet, "Orders.count")}
/>

/<chart>/<chart>/<chart>







<chart> cubejsApi={cubejsApi}
title="New Users Over Time"
query={{
measures: ["Users.count"],
timeDimensions: [
{

dimension: "Users.createdAt",
dateRange: ["2017-01-01", "2018-12-31"],
granularity: "month"
}
]
}}
render={resultSet => (
<responsivecontainer>
<areachart>
<xaxis>
<yaxis>
<tooltip>
<area> type="monotone"
dataKey="Users.count"
name="Users"
stroke="rgb(106, 110, 229)"
fill="rgba(106, 110, 229, .16)"
/>
/<areachart>
/<responsivecontainer>
)}
/>


<chart> cubejsApi={cubejsApi}
title="Orders by Status Over time"
query={{
measures: ["Orders.count"],
dimensions: ["Orders.status"],
timeDimensions: [
{
dimension: "Orders.createdAt",
dateRange: ["2017-01-01", "2018-12-31"],
granularity: "month"
}
]
}}
render={resultSet => {
return (
<responsivecontainer>
<barchart>
<xaxis>
<yaxis>
stackId="a"
dataKey="shipped, Orders.count"
name="Shipped"
fill="#7DB3FF"
/>

stackId="a"
dataKey="processing, Orders.count"
name="Processing"
fill="#49457B"
/>
stackId="a"
dataKey="completed, Orders.count"
name="Completed"
fill="#FF7C78"
/>
<legend>
<tooltip>
/<barchart>
/<responsivecontainer>
);
}}
/>

/<chart>/<chart>

/<container>
);
}
}

export default App;

這足以構建第一個儀表板,然後可以在下面的 CodeSanbox 中嘗試一下。


分享到:


相關文章: