MongoDB 实时仪表板
本文摘自使用 React 和 Cube.js 构建实时仪表盘的指南。完整指南请点击此处。
实时仪表板是指包含图表的仪表板,这些图表会使用最新的可用数据自动更新。典型的用例是先加载一些历史数据,然后在新数据到来时实时更新图表。在本教程中,您将学习如何仅使用开源工具(无需任何第三方服务)构建此类实时仪表板。
构建这样一个仪表板的主要挑战在于设计一个合适的架构,以便响应从数据库到前端图表的全程数据变化。从服务器到前端的部分比较简单,因为我们已经构建了许多用于处理实时数据更新的技术和框架。从数据库到服务器则要棘手得多。根本问题在于,大多数适合分析工作负载的数据库并没有提供开箱即用的订阅数据变化的方法。相反,它们被设计为轮询式的。
Cube.js充当数据库和分析仪表板之间的中间人,可以为前端提供基于 WebSockets 的实时 API,同时轮询数据库以了解数据的变化。
您可以在此处查看使用 Cube.js 构建的实时仪表板的演示。
在前端,Cube.js 提供了一个 API 来加载初始历史数据并订阅所有后续更新。
import cubejs from '@cubejs-client/core';
import WebSocketTransport from '@cubejs-client/ws-transport';
const cubejsApi = cubejs({
transport: new WebSocketTransport({
authorization: CUBEJS_TOKEN,
apiUrl: 'ws://localhost:4000/'
})
});
cubejsApi.subscribe({
measures: ['Logs.count'],
timeDimensions: [{
dimension: 'Logs.time',
granularity: 'hour',
dateRange: 'last 1440 minutes'
}]
}, (e, result) => {
if (e) {
// handle new error
} else {
// handle new result set
}
});
在本教程中,我们将使用 React 作为前端框架。Cube.js 有一个@cubejs-client/react
包,提供 React 组件,可轻松将 Cube.js 集成到 React 应用中。它使用 React hooks 来加载查询并订阅更改。
import { useCubeQuery } from '@cubejs-client/react';
const Chart = ({ query, cubejsApi }) => {
const {
resultSet,
error,
isLoading
} = useCubeQuery(query, { subscribe: true, cubejsApi });
if (isLoading) {
return <div>Loading...</div>;
}
if (error) {
return <pre>{error.toString()}</pre>;
}
if (!resultSet) {
return null;
}
return <LineChart resultSet={resultSet}/>;
};
在本教程中,我将向您展示如何使用 MongoDB 构建实时仪表板
。相同的方法适用于Cube.js 支持的任何数据库。
长期以来,与现代 SQL RDBMS 和数据仓库(与聚合管道和 MapReduce 实践相关)相比,使用 MongoDB 进行分析需要额外的开销。为了填补这一空白,MongoDB 发布了用于 BI 的 MongoDB 连接器,它充当 MongoDB 数据之上的 MySQL 服务器。在底层,它将现有的聚合机制桥接到 MySQL 协议,允许标准 MySQL 客户端连接并发出 SQL 查询。
设置 MongoDB 和 BI 连接器
如果您没有 MongoDB 实例,可以在此处下载。BI 连接器可以在此处下载。请确保您使用的 MongoDB 版本支持 BI 的 MongoDB 连接器。
安装 BI 连接器后,请先启动一个mongod
实例。如果您使用下载的安装,则可以从其主目录启动,如下所示:
$ bin/mongod
BI 连接器本身可以以相同的方式启动:
$ bin/mongosqld
请注意,它mongosqld
位于另一个bin
目录中。如果一切正常,您应该会在 shell 中看到该mongosqld
进程的成功日志消息:
[initandlisten] waiting for connections at 127.0.0.1:3307
如果您正在使用 MongoDB Atlas,则可以使用本指南启用 BI 连接器。
获取样本数据集
如果您的仪表板上已经有数据,则可以跳过此步骤。
我们托管了一个示例事件集合,您可以将其用作演示仪表板。使用以下命令下载并导入它。
$ curl https://cube.dev/downloads/events-dump.zip > events-dump.zip
$ unzip events-dump.zip
$ bin/mongorestore dump/stats/events.bson
请确保重新启动 MongoDB BI 连接器实例,以便从刚添加的集合中生成最新的 MySQL 模式。
创建Cube.js应用程序
我们将使用 Cube.js CLI 来创建我们的后端应用程序;让我们首先安装它。
$ npm install -g cubejs-cli
接下来,使用 MongoBI 驱动程序创建一个新的 Cube.js 应用程序。
$ cubejs create real-time-dashboard -d mongobi
转到刚刚创建的文件夹并使用您的 MongoDB 凭据real-time-dashboard
更新文件。.env
CUBEJS_DB_HOST=localhost
CUBEJS_DB_NAME=stats
CUBEJS_DB_PORT=3307
CUBEJS_DB_TYPE=mongobi
CUBEJS_API_SECRET=SECRET
现在让我们启动一个Cube.js开发服务器。
$ npm run dev
这将启动一个带有 Playground 的开发服务器。我们将使用它来生成 Cube.js 模式、测试数据,并最终构建一个仪表板。在浏览器中打开http://localhost:4000 。
Cube.js 使用数据模式生成 SQL 代码,该代码将在数据库中执行。数据模式是一段 JavaScript 代码,它定义了度量和维度以及它们如何映射到 SQL 查询。
Cube.js 可以根据数据库表生成简单的数据模式。选择events
表并点击“生成模式”。
生成模式后,我们可以导航到“构建”选项卡,选择一些度量和维度来测试模式。在“构建”选项卡中,您可以使用不同的可视化库构建示例图表,并检查图表的创建过程,从生成的 SQL 一直到用于渲染图表的 JavaScript 代码。您还可以检查发送到 Cube.js 后端的 JSON 查询。
虽然自动生成的模式是一个很好的入门方法,但在许多情况下,您需要在 Cube.js 模式中添加更复杂的逻辑。您可以在此处了解有关数据模式及其功能的更多信息。在我们的案例中,我们
希望为实时仪表板创建几个高级度量和维度。
将的内容替换schema/Events.js
为以下内容。
cube(`Events`, {
sql: `SELECT * FROM stats.events`,
refreshKey: {
sql: `SELECT UNIX_TIMESTAMP()`
},
measures: {
count: {
type: `count`
},
online: {
type: `countDistinct`,
sql : `${anonymousId}`,
filters: [
{ sql: `${timestamp} > date_sub(now(), interval 3 minute)` }
]
},
pageView: {
type: `count`,
filters: [
{ sql: `${eventType} = 'pageView'` }
]
},
buttonClick: {
type: `count`,
filters: [
{ sql: `${eventType} = 'buttonCLicked'` }
]
}
},
dimensions: {
secondsAgo: {
sql: `TIMESTAMPDIFF(SECOND, timestamp, NOW())`,
type: `number`
},
anonymousId: {
sql: `anonymousId`,
type: `string`
},
eventType: {
sql: `eventType`,
type: `string`
},
timestamp: {
sql: `timestamp`,
type: `time`
}
}
});
首先,我们为仪表板定义度量。度量count
只是对所有事件总数的简单计数;pageView
并且buttonClick
是相应事件的计数。online
度量稍微复杂一些。它返回过去 3 分钟内执行过任何事件的唯一用户数量。
其中,dimensions
我们有简单的anonymousId
、eventType
和timestamp
,它们仅显示相应列的值。我们还定义了一个secondsAgo
维度,用于计算事件发生以来的秒数。
最后,我们设置一个自定义的refreshKey。它控制
Cube.js 内存缓存层的刷新。设置为 ,每秒刷新一次缓存。您需要根据数据仔细选择最佳的刷新策略,以便在需要时获取最新的数据,同时避免数据库因大量不必要的查询而负担过重。SELECT
UNIX_TIMESTAMP()
到目前为止,我们已经成功配置了数据库,并创建了 Cube.js 模式作为我们的仪表板。现在是时候构建仪表板本身了!
Cube.js Playground 可以生成一个样板前端应用。这是
一种便捷的方式,可以开始开发仪表板或分析应用程序。您可以选择自己喜欢的前端框架和图表库,Playground 将生成一个新的应用程序,并将所有内容连接在一起,以便与 Cube.js 后端 API 配合使用。
我们将在本教程中使用 React 和 Chart.js。要创建新应用,请导航至“Dashboard App”,选择“React Antd Static”和“Chart.js”,然后点击“创建仪表盘应用”按钮。
生成应用程序并安装所有依赖项可能需要一些时间。完成后,dashboard-app
你的 Cube.js 项目文件夹中会有一个文件夹。要启动仪表板应用程序,请前往 Playground 中的“仪表板应用程序”选项卡,然后点击“启动”按钮,或者在文件夹中运行以下命令dashboard-app
:
$ npm start
确保 Cube.js 后端进程已启动并运行,因为我们的仪表板使用了它的 API。前端应用程序在http://localhost:3000上运行。
要在仪表板上添加图表,您可以编辑dashboard-app/src/pages/DashboardPage.js
文件或使用 Cube.js Playground。要通过 Playground 添加图表,请导航至“构建”选项卡,构建所需的图表,然后点击“添加到仪表板”按钮。
配置 Cube.js 以实现实时数据获取
为了在 Cube.js 中实现实时支持,我们需要做一些事情。首先,
通过设置环境变量在后端启用 WebSockets 传输CUBEJS_WEB_SOCKETS
。
将以下行添加到.env
文件。
CUBEJS_WEB_SOCKETS=true
接下来,我们需要更新index.js
文件以将一些附加选项传递给 Cube.js 服务器。
更新文件内容index.js
如下。
const CubejsServer = require('@cubejs-backend/server');
const server = new CubejsServer({
processSubscriptionsInterval: 1,
orchestratorOptions: {
queryCacheOptions: {
refreshKeyRenewalThreshold: 1,
}
}
});
server.listen().then(({ port }) => {
console.log(`🚀 Cube.js server is listening on ${port}`);
}).catch(e => {
console.error('Fatal error during server start: ');
console.error(e.stack || e);
});
我们向 Cube.js 后端传递了两个配置选项。第一个配置processSubscriptionsInterval
选项控制轮询间隔。默认值为 5 秒;我们将其设置为 1 秒,以提高实时性。
秒,refreshKeyRenewalThreshold
控制执行的频率refreshKey
。此选项的默认值为 120,即 2 分钟。在上一部分中,我们已将其更改refreshKey
为每秒重置一次缓存,因此再等待 120 秒来使结果本身无效是没有意义的refreshKey
,因此我们也将其更改为 1 秒。
这就是我们需要在后端进行的所有更新。现在,让我们更新仪表板应用程序的代码。首先,让我们安装该@cubejs-client/ws-transport
软件包。它提供了一个 WebSocket 传输,以便与 Cube.js 实时 API 配合使用。
在终端中运行以下命令。
$ cd dashboard-app
$ npm install -s @cubejs-client/ws-transport
接下来,更新src/App.js
文件以使用实时传输与 Cube.js API 协同工作。
-const API_URL = "http://localhost:4000";
+import WebSocketTransport from '@cubejs-client/ws-transport';
const CUBEJS_TOKEN = "SECRET";
-const cubejsApi = cubejs(CUBEJS_TOKEN, {
- apiUrl: `${API_URL}/cubejs-api/v1`
+const cubejsApi = cubejs({
+ transport: new WebSocketTransport({
+ authorization: CUBEJS_TOKEN,
+ apiUrl: 'ws://localhost:4000/'
+ })
});
现在,我们需要更新在 中请求查询本身的方式src/components/ChartRenderer.js
。请进行以下更改。
-const ChartRenderer = ({ vizState }) => {
+const ChartRenderer = ({ vizState, cubejsApi }) => {
const { query, chartType } = vizState;
const component = TypeToMemoChartComponent[chartType];
- const renderProps = useCubeQuery(query);
+ const renderProps = useCubeQuery(query, { subscribe: true, cubejsApi });;
return component && renderChart(component)(renderProps);
};
就这样!现在,您可以向仪表板添加更多图表,在数据库中执行更改,并查看图表的实时更新情况。
下面的 GIF 动图展示了仪表盘,其中包含事件总数、在线用户数以及包含最新事件的表格。当我在数据库中插入新数据时,您可以看到图表实时更新。
您还可以查看此在线实时演示,其中有显示实时数据的各种图表。
恭喜你完成本指南!🎉
我很乐意听听您遵循本指南的体验,请随时在下面发表评论!
要了解如何部署此仪表板,您可以在此处查看实时仪表板指南的完整版本。
文章来源:https://dev.to/keydunov/real-time-dashboard-with-mongodb-5gnd