GMTC北京站9折购票倒计时,部分日程已上线,戳此查看 了解详情
写点什么

Cube.js:开源仪表板框架的终极指南

  • 2019 年 4 月 14 日
  • 本文字数:7163 字

    阅读完需:约 24 分钟

Cube.js:开源仪表板框架的终极指南

Cube.js是一个用于构建分析 web 应用程序的开源框架,主要用于构建内部的商业智能工具或将面向客户的分析添加到现有的应用程序当中。大多数情况下,构建此类应用程序的第一步是分析仪表板。通常从“在管理面板中添加一个分析仪表板”开始,然后就像软件开发中经常发生的那样,事情会变得更加复杂。


当开始使用 Cube.js 时,会想要构建一个工具,它起初很简单,但在功能、复杂性和数据量方面很容易扩展。Cube.js 为未来的分析系统奠定坚实的基础,无论是独立的应用程序还是嵌入到现有的分析系统中。


本教程可以视为“Cube.js 101”,它介绍了从数据库到可视化的第一个仪表板的基本设计步骤。


最终仪表板的现场演示可在此处获得。完整的源代码在 GitHub上。


架构

大多数现代 web 应用程序都是作为单页面应用程序构建的,前端与后端分离。遵循微服务架构,后端通常也会分成多个服务。


通常,Cube.js 的后端作为服务运行,管理与数据库的连接,包括查询队列、缓存、预聚合等。同时为前端应用程序公开一个 API,用于构建仪表板和其他分析功能。



后端

分析从数据产生并驻留在数据库中开始,如果用户已经有一个适用于应用程序的数据库,通常它可以直接用于分析。现代流行的数据库,如 Postgres 或 MySQL,都可以做简单的分析工作,这里的简单指的是行数少于 10 亿的数据量。


另外,MongoDB 也可以,不过需要添加 MongoDB Connector for BI。它允许在 MongoDB 数据之上执行 SQL 代码。这是免费的,可以从 MongoDB 网站直接下载。需要注意的是,出于性能问题的考虑,直接在生产数据库上运行分析查询是不好的做法。所以,即使 Cube.js 可以显著减少数据库的工作量,但仍然建议连接到副本。


总而言之,如果使用 Postgres 或 MySQL,只需创建一个副本就可以了。如果您使用 MongoDB,请下载 MongoDB Connector for BI 并创建副本。


如果没有构建仪表板的任何数据,可以加载示例中的电子商务 Postgres 数据集。


$ curl http://cube.dev/downloads/ecom-dump.sql> ecom-dump.sql$ createdb ecom$ psql  --dbname ecom -f ecom-dump.sql
复制代码


当数据库中有数据,就可以开始创建 Cube.js 的后端服务。在终端中运行以下命令:


$ npm install -g cubejs-cli$ cubejs create dashboard-backend -d postgres
复制代码


上面的命令安装 Cube.js CLI,并创建一个新服务,配置为可以与 Postgres 数据库一起使用。


Cube.js 使用环境变量进行配置,环境变量以 CUBEJS_开头。要配置与数据库的连接,需要指定数据库的类型和名称。在 Cube.js 项目文件夹中,替换.env 的以下内容:


CUBEJS_API_SECRET = SECRETCUBEJS_DB_TYPE = postgresCUBEJS_DB_NAME = ecom
复制代码


Cube.js 数据 Schema

下一步是创建一个Cube.js数据Schema。Cube.js 利用数据 Schema 生成 SQL 代码,该代码将在数据库中执行。数据 Schema 不是 SQL 的替代品,它旨在使 SQL 可重用并赋予其结构,同时保留其所有功能。数据 Schema 的基本元素是 measures 和 dimensions。


,


Measure 被称为定量数据,例如单位销售数、唯一访问量、利润等。


Dimension 被称为分类数据,例如状态、性别、产品名称或时间单位(例如,日、周、月)。


通常,模式文件位于 schema 文件夹中。以下是架构的示例,可用于描述用户的数据。


cube(`Users`,{  sql:`SELECT * FROM users`,    measures:{    count:{      sql:`id`,      type:`count`    }  },    dimensions:{    city:{      sql:`city`,      type:`string`    },        signedUp:{      sql:`created_at`,      type:`time`    },        companyName:{      sql:`company_name`,      type:`string`    }  }});
复制代码


现在,通过上述 Schema,可以向 Cube.js 后端发送有关用户数据的查询。Cube.js 查询是纯 JavaScript 对象。通常情况下,它有一个或多个 measures、dimensions 和 timeDimensions。


如果要回答“用户在哪里?”这个问题,可以将以下查询发送到 Cube.js:


{   measures: ['Users.count'],   dimensions: ['Users.city']}
复制代码


Cube.js 将根据 Schema 生成所需的 SQL,执行它并将结果发回。


我们可以创建一个稍微复杂的查询,添加一个 timeDimensions,看看去年不同城市的比例在每个月是如何变化的。为此,需要添加 signedUp 时间维度,按月分组,并仅包含去年的注册。


{   measures: ['Users.count'],   dimensions: ['Users.city'],   timeDimensions: [{     dimension: 'Users.signedUp',     granularity: 'month',     dateRange: ['2018-01-31', '2018-12-31']   }]}
复制代码


Cube.js 还可以根据数据库的表生成简单的 Schema,并需要为仪表板生成所需的 Schema,启动一个供开发的服务器。


$ cubejs generate -t users,orders$ npm run dev
复制代码


可以通过在http://localhost:4000打开开发后台,检查生成的 Schema 并发送测试的查询。


前端

通过 Cube.js 的 React 客户端,可以使用 React 来构建前端和仪表板。也可以使用任何框架或只使用 vanilla JavaScript 来构建 Cube.js 的前端,这个教程将向您展示如何在纯JavaScript中构建仪表板。我们将使用 React 团队正式支持的 Create React App 来设置所有内容,它打包了 React 应用程序的所有依赖项,可以轻松地开始使用新项目。在终端中运行以下命令:


$ npx create-react-app dashboard-frontend$ cd cubejs-dashboard$ npm start
复制代码


最后一行在端口 3000 上启动服务器,并通过http://localhost:3000打开 web 浏览器。


我们将使用 Reactstrap 来构建我们的 UI,它是 Bootstrap 4 的 React wrapper。用 NPM 来安装 Reactstrap 和 Bootstrap。Reactstrap 不包括 Bootstrap CSS,所以需要单独安装:


$ npm install reactstrap bootstrap --save
复制代码


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


import 'bootstrap/dist/css/bootstrap.min.css';
复制代码


现在,我们已准备好使用 Reactstrap 组件。


下一步是安装 Cube.js 客户端,这样可以从服务器和可视化库中获取数据并进行显示。在本教程中,我们将使用 Recharts。Cube.js 是可视化不可知的,这意味着可以使用任何所需的库。我们还将使用 moment 和 numeral 来很好地格式化日期和数字。


$ npm install --save @ cubejs-client / core @ cubejs-client / react recharts moment numbers
复制代码


这样,我们搞定了依赖关系。接下来继续创建我们的第一个图表,用以下替换 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 width="100%" height={300}> <BarChart data={resultSet.chartPivot()}> <XAxis dataKey="x" tickFormatter={dateFormatter} /> <YAxis /> <Tooltip labelFormatter={dateFormatter} /> <Bar dataKey="Orders.count" fill="rgba(106, 110, 229)" /> </BarChart> </ResponsiveContainer> ); }} /> ); }}
export default App;
复制代码


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



接下来,让我们更深入地了解如何加载数据并绘制图表。


首先,我们初始化 Cube.js API 客户端:


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


这里,我们使用 REACT_APP_CUBEJS_TOKEN 和 REACT_APP_API_URL 这两个环境变量。如果环境变量以 REACT_APP_开头,Create React App 会自动从.env 文件中加载。Cube.js 后端将在启动期间打印这些 API token。



使用正确的凭据创建.env 文件。


REACT_APP_CUBEJS_TOKEN=COPY-API-TOKEN-FROM-TERMINAL-OUTPUTREACT_APP_API_URL=http://localhost:4000/cubejs-api/v1
复制代码


接下来,我们使用 QueryRenderer Cube.js React Component 来加载 Orders 数据。


<QueryRenderer  query={{    measures: ["Orders.count"],    timeDimensions: [      {        dimension: "Orders.createdAt",        dateRange: ["2017-01-01", "2018-12-31"],        granularity: "month"      }    ]  }}  cubejsApi={cubejsApi}  render={({ resultSet }) => {    // Render result  }}/>
复制代码


QueryRenderer 对 Cube.js 后端执行 API 请求,并根据需要使用render props技术来渲染结果。我们上面已经介绍了查询格式,想得到最新的格式,这里是查询格式的完整参考。


QueryRenderer 的参数 render,是几个类型的函数({error, resultSet, isLoading}) => React.Node。该函数的输出将由  QueryRenderer 提供。resultSet 是从查询获得的数据对象,如果未定义此对象,则表示仍在提取数据中。


resultSet 提供了多种数据操作方法,但在我们的例子中,只需要 chartPivot 方法,它以 Recharts 预期的格式返回数据。


我们将订单数据绘制成响应式容器内的条形图。


if (!resultSet) {  return "Loading...";}return (  <ResponsiveContainer width="100%" height={300}>    <BarChart data={resultSet.chartPivot()}>      <XAxis dataKey="x" tickFormatter={dateFormatter} />      <YAxis />      <Tooltip labelFormatter={dateFormatter} />      <Bar dataKey="Orders.count" fill="rgba(106, 110, 229)" />    </BarChart>  </ResponsiveContainer>);
复制代码


构建仪表板

我们学习了如何使用 Cube.js 和 Recharts 构建单个图表,现​​在可以开始构建整个仪表板。可以找到设计仪表板布局的一些最佳实践,通常的做法是将最重要和最高级别的指标放在顶部作为单值图表(有时称为KPI),然后列出这些指标的相关细节。


以下是最终仪表板的屏幕截图,其中 KPI 位于顶部,下面是条形图和折线图。



首先,让我们重构图表,并将公共代码提取到可重用的组件中。用以下的内容创建一个 src/Chart.js 文件:


import React from "react";import { Card, CardTitle, CardBody, CardText } from "reactstrap";import { QueryRenderer } from "@cubejs-client/react";
const Chart = ({ cubejsApi, title, query, render }) => ( <Card> <CardBody> <CardTitle tag="h5">{title}</CardTitle> <CardText> <QueryRenderer query={query} cubejsApi={cubejsApi} render={({ resultSet }) => { if (!resultSet) { return <div className="loader" />; } return render(resultSet); }} /> </CardText> </CardBody> </Card>);
export default Chart;
复制代码


接下来,让我们使用此组件来创建仪表板。用以下内容替换 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) => ( <h1 height={300}>{numberFormatter(resultSet.chartPivot()[0][key])}</h1>);
class App extends Component { render() { return ( <Container fluid> <Row> <Col sm="4"> <Chart cubejsApi={cubejsApi} title="Total Users" query={{ measures: ["Users.count"] }} render={resultSet => renderSingleValue(resultSet, "Users.count")} /> </Col> <Col sm="4"> <Chart cubejsApi={cubejsApi} title="Total Orders" query={{ measures: ["Orders.count"] }} render={resultSet => renderSingleValue(resultSet, "Orders.count")} /> </Col> <Col sm="4"> <Chart cubejsApi={cubejsApi} title="Shipped Orders" query={{ measures: ["Orders.count"], filters: [ { dimension: "Orders.status", operator: "equals", values: ["shipped"] } ] }} render={resultSet => renderSingleValue(resultSet, "Orders.count")} /> </Col> </Row> <br /> <br /> <Row> <Col sm="6"> <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 width="100%" height={300}> <AreaChart data={resultSet.chartPivot()}> <XAxis dataKey="category" tickFormatter={dateFormatter} /> <YAxis tickFormatter={numberFormatter} /> <Tooltip labelFormatter={dateFormatter} /> <Area type="monotone" dataKey="Users.count" name="Users" stroke="rgb(106, 110, 229)" fill="rgba(106, 110, 229, .16)" /> </AreaChart> </ResponsiveContainer> )} /> </Col> <Col sm="6"> <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 width="100%" height={300}> <BarChart data={resultSet.chartPivot()}> <XAxis tickFormatter={dateFormatter} dataKey="x" /> <YAxis tickFormatter={numberFormatter} /> <Bar stackId="a" dataKey="shipped, Orders.count" name="Shipped" fill="#7DB3FF" /> <Bar stackId="a" dataKey="processing, Orders.count" name="Processing" fill="#49457B" /> <Bar stackId="a" dataKey="completed, Orders.count" name="Completed" fill="#FF7C78" /> <Legend /> <Tooltip /> </BarChart> </ResponsiveContainer> ); }} /> </Col> </Row> </Container> ); }}
export default App;
复制代码


这足以构建第一个仪表板,然后可以在下面的 CodeSanbox 中尝试一下。


下一步

以上是我们使用 Cube.js 构建了一个简单的验证概念的仪表板。可以在这里查看现场演示。GitHub 有完整的源代码


要了解有关 Cube.js 后端部署的更多信息,可以参考部署文档。此外,还可以在此处找到有关各种主题的更多教程


原文链接Cube.js: Ultimate Guide to the Open-Source Dashboard Framework


2019 年 4 月 14 日 15:3827855
用户头像

发布了 40 篇内容, 共 30.1 次阅读, 收获喜欢 129 次。

关注

评论

发布
暂无评论
发现更多内容

数据分析从零开始实战,Pandas读写Excel/XML数据

老表

Python 数据分析 Excel pandas 11月日更

JSON 数据格式

大数据技术指南

11月日更

深入学习 SAP UI5 框架代码系列之二:UI5 控件的渲染器

Jerry Wang

SAP 签约计划第二季 ui5 渲染器 技术专题合集

Exchange漏洞分析:SSRF RCE

网络安全学海

网络安全 信息安全 渗透测试 WEB安全 安全漏洞

CloudPosse 的 Terraform 最佳实践

大可不加冰

DevOps 基础设施即代码 IaC Terraform HashiCorp

【死磕Java并发】-----J.U.C之Condition

chenssy

11月日更 死磕 Java 死磕 Java 并发

限流系列文章——滑动窗口限流

李子捌

redis 限流 签约计划第二季

【高并发】如何使用Java7提供的Fork/Join框架实现高并发程序?

冰河

Java 并发编程 多线程 高并发 异步编程

URL URI傻傻分不清楚,dart告诉你该怎么用

程序那些事

flutter dart 程序那些事 11月日更

跟小师妹一起学JVM-系列文章

程序那些事

Java JVM JIT 内容合集 签约计划第二季

新成就!OceanBase 入选 Forrester 首份分布式数据库报告

OceanBase 数据库

数据库 开源 新闻 oceanbase 荣誉

畅聊分布式体系架构

DisonTangor

分布式架构

为什么我的 C4C Service Request 没办法 Release 到 ERP?

Jerry Wang

Cloud SAP abap C4C 11月日更

Flutter自定义日历【Flutter 专题 11】

坚果

flutter 签约计划第二季

盘点Flutter领域的点点滴滴 【专题合集】

坚果

flutter 内容合集 签约计划第二季 技术专题合集

Prometheus Exporter (十三)Elasticsearch Exporter

耳东@Erdong

elasticsearch Prometheus exporter 11月日更

李子捌 Redis精通系列文章 研究分享| 内容合集

李子捌

redis 内容合集 签约计划第二季 技术专题合集

k8s statefulset controller源码分析

良凯尔

源码 Kubernetes 源码分析 #Kubernetes#

云原生训练营作业--部署k8s集群

好吃不贵

2021年大数据开发发展趋势

五分钟学大数据

11月日更

深入学习 SAP UI5 框架代码系列之一:UI5 Module 的懒加载机制

Jerry Wang

JavaScript SAP 签约计划第二季 ui5 技术专题合集

音视频理论(1)- 音频格式之 Monkeys Audio(APE)

liuzhen007

签约计划第二季

Flutter 2.5 的新特性【Flutter专题12】

坚果

flutter 签约计划第二季

[Pulsar] 消息从Producer到Broker的历程

Zike Yang

Apache Pulsar 11月日更

CSS之盒模型

Augus

CSS 11月日更

Linux 调优之:调整 bond hash 策略提升网络吞吐能力

卫智雄

SAP Cloud for Customer Price 计价简介

Jerry Wang

Cloud SAP C4C 11月日更 pricing

转型中的学习型组织 ——阅读《第五项修炼》有感

数字化转型Jojo

系统性思考 企业转型

Flutter 中的手势【Flutter 专题10】

坚果

flutter 签约计划第二季

深入学习 SAP UI5 框架代码系列之三:HTML 原生事件 VS UI5 Semantic 事件

Jerry Wang

JavaScript SAP 签约计划第二季 HTML原生事件 技术专题合集

Cube.js:开源仪表板框架的终极指南_开源_Artyom Keydunov_InfoQ精选文章