visit
You can skip this step if you already have some data for your dashboard
If you don’t have a local MongoDB instance, please download it . The BI Connector can be downloaded .There is a good with a curated list of JSON / BSON datasets from the web in order to practice in MongoDB. We’ll pick a for our dashboard. and import it using the following command in your MongoDB directory.$ bin/mongorestore Your-Downloads-Folder/dump/twitter/tweets.bson
# Run from MongoDB directory
$ bin/mongod
# Run from MongoDB BI Connector directory
$ bin/mongosqld
# Install it if you don’t have it already
$ npm install express-generator -g
$ express --view=hbs express-analytics-dashboard
$ npm install --save @cubejs-backend/server-core @cubejs-backend/mongobi-driver dotenv
We’ve added a core server package for Cube.js and the Cube.js MongoBI driver. We’ve also added a
dotenv
package to manage our credentials. Let’s create a .env
file with the following credentials; we need them to tell Cube.js how to connect to Mongo.CUBEJS_DB_HOST=localhost
CUBEJS_DB_NAME=twitter
CUBEJS_DB_PORT=3307
CUBEJS_DB_TYPE=mongobi
CUBEJS_API_SECRET=SECRET
Now, let’s mount the Cube.js Server into our express application. Add the following code right after the routes declaration in your
app.js
.var CubejsServerCore = require('@cubejs-backend/server-core');
// ...
app.use('/', indexRouter);
require('dotenv').config();
CubejsServerCore.create().initApp(app);
// ...
With the above two lines of code, we have loaded all required configs from the
.env
file and mounted Cube.js into our Express app. By default, it’s mounted into the /cubejs-api/v1/
path namespace. But you can change it and a lot of other things by passing the to the CubejsServerCore.create()method
. We’ll keep the default settings for our tutorial.Now, let’s create a Cube.js Schema for our tweets table. Cube.js uses Data Schema to generate and execute SQL; Create a folder,
schema
, with a Tweets.js
file inside with the following content.cube(`Tweets`, {
sql: `select * from tweets`,
measures: {
count: {
type: `count`
},
favoriteCount: {
type: `sum`,
sql: `favorite_count`
},
retweetCount: {
type: `sum`,
sql: `retweet_count`
}
},
dimensions: {
location: {
type: `string`,
sql: `\`user.location\``
},
lang: {
type: `string`,
sql: `lang`
}
}
});
In Cube.js, you can describe your queries in Javascript and then they will be compiled into SQL and executed inside your database. It uses
measures
and dimensions
as basic units to describe various analytics queries. Now let’s move on to building a dashboard on the frontend.$ npm install -g cubejs-cli
$ cubejs create -d mongobi -t serverless
<link rel="stylesheet" href="//stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/numeral.js/2.0.6/numeral.min.js"></script>
<script src="//unpkg.com/@cubejs-client/[email protected]/dist/cubejs-client-core.js"></script>
<div class="container" id="app">
<div class="row">
<div class="col-md-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">Total Tweets</h5>
<div class="card-text">
<h3 id="total-tweets"></h3>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">Total Retweets</h5>
<div class="card-text">
<h3 id="total-retweets"></h3>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">Total Favorites</h5>
<div class="card-text">
<h3 id="total-favorites"></h3>
</div>
</div>
</div>
</div>
</div>
<br />
<br />
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="card-body">
<h5 class="card-title">Top Tweets Locations</h5>
<div class="card-text">
<canvas id="pie-chart"></canvas>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-body">
<h5 class="card-title">Most Popular Languages</h5>
<div class="card-text">
<canvas id="bar-chart"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
var cubejsApi = cubejs(
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTIzOTk5MjcsImV4cCI6MTU1MjQ4NjMyN30.SOO-A6GfGH7ar3EoeBb0cjj10BVxO3ffjvmqQziXIZA',
{ apiUrl: '//localhost:3000/cubejs-api/v1' }
);
var kpis = [
{ measure: "Tweets.count", element: "total-tweets" },
{ measure: "Tweets.retweetCount", element: "total-retweets" },
{ measure: "Tweets.favoriteCount", element: "total-favorites" }
];
kpis.forEach(kpi => {
cubejsApi.load({
measures: [kpi.measure]
}).then(resultSet => {
document.getElementById(kpi.element).textContent =
numeral(resultSet.totalRow()[kpi.measure]).format('0,0');
})
});
// A helper method to format data for Chart.js
// and add some nice colors
var chartJsData = function(resultSet) {
return {
datasets: [{
data: resultSet.series()[0].series.map(function(r) { return r.value }),
backgroundColor: [
'rgb(255, 99, 132)',
'rgb(255, 159, 64)',
'rgb(255, 205, 86)',
'rgb(75, 192, 192)',
'rgb(54, 162, 235)'
]
}],
labels: resultSet.categories().map(function(c) { return c.category })
}
}
cubejsApi.load({
measures: ["Tweets.count"],
dimensions: ["Tweets.location"],
filters: [
{
dimension: "Tweets.location",
operator: "notEquals",
values: [""]
}
],
limit: 5
}).then(resultSet => {
new Chart(document.getElementById("pie-chart"), {
type: 'pie',
data: chartJsData(resultSet)
})
});
cubejsApi.load({
measures: ["Tweets.count"],
dimensions: ["Tweets.lang"],
limit: 5
}).then(resultSet => {
new Chart(document.getElementById("bar-chart"), {
type: 'bar',
data: chartJsData(resultSet),
options: { legend: { display: false } }
})
});
</script>
<link rel="stylesheet" href="//stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/numeral.js/2.0.6/numeral.min.js"></script>
<script src="//unpkg.com/@cubejs-client/[email protected]/dist/cubejs-client-core.js"></script>
var cubejsApi = cubejs(
'YOUR-API-TOKEN',
{ apiUrl: '//localhost:3000/cubejs-api/v1' }
);
var kpis = [
{ measure: "Tweets.count", element: "total-tweets" },
{ measure: "Tweets.retweetCount", element: "total-retweets" },
{ measure: "Tweets.favoriteCount", element: "total-favorites" }
];
kpis.forEach(kpi => {
cubejsApi
.load({
measures: [kpi.measure]
})
.then(resultSet => {
document.getElementById(kpi.element).textContent = numeral(
resultSet.totalRow()[kpi.measure]
).format("0,0");
});
});
The row has one pie and one bar chart, plotted with Chart.js. To display the bar chart, we’re requesting the
Tweets.count
measure and grouping it by the Tweets.location
dimension. We’re also applying a filter to exclude tweets with an empty location. Finally, we’re setting the limit to 5 to get only the top 5 locations.You can learn more about the Cube.js Query format here.For the bar chart, we’re doing a similar grouping, but instead of location, we’re grouping by the
Tweets.lang
dimension.// A helper method to format data for Chart.js
// and add some nice colors
var chartJsData = function(resultSet) {
return {
datasets: [
{
data: resultSet.series()[0].series.map(function(r) {
return r.value;
}),
backgroundColor: [
"rgb(255, 99, 132)",
"rgb(255, 159, 64)",
"rgb(255, 205, 86)",
"rgb(75, 192, 192)",
"rgb(54, 162, 235)"
]
}
],
labels: resultSet.categories().map(function(c) {
return c.category;
})
};
};
cubejsApi
.load({
measures: ["Tweets.count"],
dimensions: ["Tweets.location"],
filters: [
{
dimension: "Tweets.location",
operator: "notEquals",
values: [""]
}
],
limit: 5
})
.then(resultSet => {
new Chart(document.getElementById("pie-chart"), {
type: "pie",
data: chartJsData(resultSet)
});
});
cubejsApi
.load({
measures: ["Tweets.count"],
dimensions: ["Tweets.lang"],
limit: 5
})
.then(resultSet => {
new Chart(document.getElementById("bar-chart"), {
type: "bar",
data: chartJsData(resultSet),
options: { legend: { display: false } }
});
});
$ npm start