Create a real-time data analytics platform with Appwrite and Nuxtjs

Tosin Moronfolu - Feb 3 '23 - - Dev Community

Creating a real-time data analytics platform can be challenging, but it can be made much easier with the right tools. One such tool is Appwrite, a modern and powerful backend-as-a-service (BaaS) platform for easily building and deploying web and mobile applications. Another helpful tool is Nuxt.js, a progressive framework for building server-rendered Vue.js applications.

This article covers the steps to create a real-time data analytics platform using Appwrite and Nuxt.js by simulating a simple eCommerce dashboard.

Repository

Here’a a link to the repo:

https://github.com/folucode/data-visualization-appwrite

Prerequisites

  • Basic understanding of CSS, JavaScript, and Nuxt.js
  • Docker Desktop installed on your computer (run the docker -v command to verify the installation); if not, install it from here
  • An Appwrite instance running on your computer. Check out this post to create a local Appwrite instance. It can also be installed using digital ocean or gitpod

Setting up the project

Create a new Nuxt.js project using the following command:

npx create-nuxt-app data-analytics-platform
Enter fullscreen mode Exit fullscreen mode

This will guide you through several prompts to set up the project, including selecting a package manager, a UI framework, and additional features. Make sure to choose Axios as the HTTP client, as you'll use it to make API calls to Appwrite later.

Once you finish setting up the project, you can navigate to the project directory and start the development server using the following commands:

cd data-analytics-platform
npm run dev
Enter fullscreen mode Exit fullscreen mode

Setting up an Appwrite database

To set up an Appwrite storage bucket, log in to the Appwrite console and create a new project. Next, click on the Databases tab and then Create database. You can give it the name of ecommerce.

image

Click on the ecommerce database and create a new collection in the database; call it orders. Collections serve as database tables in Appwrite.

Next, click on the collection, and then add new attributes. Attributes serve as database columns in Appwrite.

image

The attributes you will add are:

  • customer of type string
  • price of type double

Click on the settings tab, scroll down to permissions, and add Users role with all permissions for the orders collection.

image

Setting up the UI

In the components folder, create a file called DataCard.vue and paste the code below into it:

    <template>
      <div class="chart">
        <div class="chart-inner stat-1">
          <div class="header">
            <div class="tagline">{{ tagline }}</div>
            <div class="count">{{ count }}</div>
          </div>
        </div>
      </div>
    </template>

    <script>
    export default {
      props: {
        tagline: String,
        count: Number,
      },
      name: "DataCard",
    };
    </script>
Enter fullscreen mode Exit fullscreen mode

This component is a simple card that will display the order details. There are two attributesL: tagline and count.

Next, in the index.vue file, paste the code below:

    <template>
      <div>
        <div class="container-fluid">
          <DataCard tagline="Total Customers" :count="totalCustomers" />
          <DataCard tagline="Total Orders" :count="totalOrders" />
          <DataCard tagline="Total Revenue" :count="Math.round(totalRevenue)" />
        </div>

        <button class="button" @click.prevent="makeOrder()">Create Order</button>

        <h2>Orders</h2>
        <table>
          <tr>
            <th>Order ID</th>
            <th>Customer</th>
            <th>Price</th>
          </tr>
          <tr v-for="order in orders" :key="order.$id">
            <td>{{ order.$id }}</td>
            <td>{{ order.customer }}</td>
            <td>{{ order.price }}</td>
          </tr>
        </table>
      </div>
    </template>

    <script>
    export default {
      name: "IndexPage",
      data() {
        return {
          orders: [],
          totalCustomers: 0,
          totalOrders: 0,
          totalRevenue: 0,
        };
      },
      methods: {},
      mounted() {},
    };
    </script>

    <style>
    body {
      background-color: #252830;
      color: white;
    }
    .container-fluid {
      margin-left: 18%;
    }
    .chart {
      text-align: left;
      display: inline-block;
      width: 300px;
    }
    .chart-inner {
      background-color: rgba(233, 164, 164, 0.5);
    }
    .header {
      box-sizing: border-box;
      padding: 30px 15px;
      position: relative;
      text-shadow: 1px 1px 2px black;
    }
    .tagline {
      opacity: 0.75;
      text-transform: uppercase;
    }
    .count {
      display: inline-block;
      font-size: 32px;
      font-weight: 300;
      vertical-align: middle;
    }
    table {
      font-family: arial, sans-serif;
      border-collapse: collapse;
      width: 100%;
    }
    td,
    th {
      border: 1px solid #dddddd;
      text-align: left;
      padding: 8px;
    }
    .button {
      background-color: #4caf50; /* Green */
      border: none;
      color: white;
      padding: 15px 32px;
      text-align: center;
      text-decoration: none;
      display: inline-block;
      font-size: 16px;
    }
    </style>
Enter fullscreen mode Exit fullscreen mode

In this file, there is a DataCard to show Total Customers, Total Revenue, and Total Orders. You have a button to create an order, and this helps to save the time of building an order system since you're primarily interested in the real-time feature. The button has a click event with a function, makeOrder(), that you'll create later.

There's also a table to list all the orders in the Appwrite database.

Building the App

Before you continue, install these two packages: the Appwrite official package and faker.js, a library to generate mock data.

npm i appwrite @faker-js/faker
Enter fullscreen mode Exit fullscreen mode

Connecting to Appwrite

In the pages/index.vue file, import the Appwrite package and the faker.js package, and then create an Appwrite connection like so:

    ...
    <script>
    import { Client, Account, Databases } from "appwrite";
    import { faker } from "@faker-js/faker";

    const client = new Client();

    client
      .setEndpoint("http://localhost/v1") // The Appwrite Endpoint
      .setProject("[YOUR-PROJECT-ID]");

    const account = new Account(client);
    const database = new Databases(client);

    account.createAnonymousSession().then(
      (response) => {
        console.log(response);
      },
      (error) => {
        console.log(error);
      }
    );

    export default {
      name: "IndexPage",
      data() {
        return {
          orders: [],
          totalCustomers: 0,
          totalOrders: 0,
          totalRevenue: 0,
        };
      },
      methods: {},
      mounted() {},
    };
    </script>
    ...
Enter fullscreen mode Exit fullscreen mode

In this file, you create an Appwrite instance along with an account and database, which you'll use later in the app. Also, set up an anonymous sessiont — this saves us the time of making a whole authentication system.

In the mounted method, check whether the anonymous account is active and subscribe to the documents channel. Subscribing to a channel updates your app in real time once a change is made in the database.

    ...
     mounted() {
        if (account.get !== null) {
          try {
            client.subscribe("documents", (response) => {
            });
          } catch (error) {
            console.log(error, "error");
          }
        }
      }
    ...
Enter fullscreen mode Exit fullscreen mode

Making an order

Add a new method to the methods object called makeOrder. In this new method, you'll create a new order in the Appwrite database using faker.js, like so:

    async makeOrder() {
      await database.createDocument(
        "[YOUR-DATABASE-ID]",
        "[YOUR-COLLECTION-ID]",
        "unique()",
        {
          customer: faker.name.fullName(),
          price: faker.finance.amount(),
        }
      );
    },
Enter fullscreen mode Exit fullscreen mode

Analyzing the data

To analyze the data, create a function called visualizeData and add the code below:

    async visualizeData() {
      const orderDetails = await database.listDocuments(
        "[YOUR-DATABASE-ID]",
        "[YOUR-COLLECTION-ID]"
     );

      this.orders = orderDetails.documents;
      this.totalCustomers = orderDetails.total;
      this.totalOrders = orderDetails.total;

      this.totalRevenue = orderDetails.documents.reduce(
        (accumulator, currentValue) => accumulator + currentValue.price,
        0
      );
    },
Enter fullscreen mode Exit fullscreen mode

In this code, you first fetch the orders from the database. The reduce function accumulates the prices to obtain the total revenue.

Every time the page reloads or changes occur in the database, you want to fetch all the podcasts in real time. To do so, call the visualizeData function in the mounted method like so:

    ...
    mounted() {
      this.visualizeData();

      if (account.get !== null) {
        try {
          client.subscribe("documents", (response) => {
            this.visualizeData();
          });
        } catch (error) {
          console.log(error, "error");
        }
      }
    },
    ...
Enter fullscreen mode Exit fullscreen mode

The app should look like so:

image

Conclusion

In conclusion, building a real-time data analytics platform with Appwrite and Nuxt.js can provide a powerful and flexible data analysis and visualization solution. By leveraging the real-time capabilities of Appwrite and the versatility of Nuxt.js, you can create dynamic and interactive dashboards that allow your users to quickly understand and explore their data in real time.

Whether you are building a platform for business analytics, IoT data analysis, or any other real-time data application, Appwrite and Nuxt.js can provide the tools and framework you need to succeed.

Resources

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .