Fermer

mars 27, 2019

Création de graphiques en temps réel avec GraphQL et Postgres


Il n'y a pas de meilleur moyen de comprendre les données que de les visualiser avec des graphiques et des diagrammes. La communauté JS a d'excellents projets à source ouverte qui facilitent la visualisation des données. Cependant, il n'y a pas eu de solution idéale pour créer des arrière-plans en temps réel capables de sauvegarder ces graphiques et de les rendre en temps réel. Avec GraphQL (qui a une spécification bien définie pour les abonnements en temps réel), nous pouvons obtenir un backend en temps réel fonctionnant en quelques secondes et l'utiliser pour générer des graphiques en temps réel.

Les graphiques forment un partie intégrante de toute industrie qui traite des données. Les graphiques sont utiles dans l’industrie du vote et des sondages, mais ils nous aident également à mieux comprendre les différents comportements et caractéristiques des utilisateurs et des clients avec lesquels nous travaillons.

Pourquoi les graphiques en temps réel sont-ils si importants? Eh bien, ils sont utiles dans les cas où de nouvelles données sont produites en continu; Par exemple, lorsque vous utilisez des séries en temps réel pour visualiser le prix des actions, vous avez tout intérêt à utiliser les graphiques en temps réel. Dans ce didacticiel, nous expliquerons comment créer des graphiques en temps réel avec des technologies open-source adaptées à cette tâche particulière.

Note : Ce didacticiel nécessite des connaissances de base de React et GraphQL. .

Stack

  1. PostgreSQL
    Le but même de l’utilisation de Charts est de visualiser des données “d’énormes” volumes. Nous avons donc besoin d’une base de données capable de gérer efficacement les données volumineuses et de fournir une API intuitive pour la restructurer. Les bases de données SQL nous permettent de créer des vues qui abstiennent et agrègent des données pour nous. Nous utiliserons Postgres, une base de données éprouvée et extrêmement efficace. Il possède également des extensions open-source sophistiquées telles que Timescale et PostGIS qui nous permettent de créer des graphiques basés sur la géolocalisation et les séries chronologiques, respectivement. Nous utiliserons Timescale pour construire notre graphique de séries chronologiques.
  2. Moteur GraphQL
    Ce message traite de la création de graphiques en temps réel, et GraphQL fournit une spécification bien définie pour les abonnements en temps réel. Hasura GraphQL Engine est un serveur open source GraphQL qui établit une connexion Postgres et vous permet d'interroger les données Postgres sur GraphQL en temps réel. Il comporte également une couche de contrôle d'accès qui vous aide à restreindre vos données en fonction de règles de contrôle d'accès personnalisées.
  3. ChartJS
    ChartJS est une bibliothèque open source populaire et bien conservée qui permet de créer des graphiques avec JavaScript. Nous allons utiliser chart.js avec son abstraction ReactJS react-chartjs-2 . Pourquoi React, c’est parce que React donne aux développeurs une API intuitive, pilotée par les événements. En outre, le flux de données unidirectionnel de React est idéal pour créer des graphiques basés sur les données.

Configuration requise

Pour ce tutoriel, vous aurez besoin des éléments suivants sur votre système:

  1. Docker CE
    Docker est un logiciel qui vous permet de conteneuriser vos applications. Une image de menu fixe est un paquet indépendant qui contient un logiciel ainsi que ses dépendances et un système d'exploitation minimaliste. De telles images de menu fixe peuvent être techniquement exécutées sur toute machine sur laquelle le menu fixe est installé. Vous aurez besoin de docker pour ce tutoriel.
  2. npm : npm est le paquet géré par JavaScript.

Démo

Nous allons construire le tableau de série chronologique en direct ci-dessous qui indique la température maximale d’un lieu par intervalles.

 Démonstration GIF du graphique en temps réel
Démonstration GIF du graphique en temps réel

Configuration de l’arrière-plan

Exécution des services

L’arrière-plan comprend d'une base de données Postgres, son extension d'échelle de temps et Hasura GraphQL Engine. Laissez la base de données et notre serveur GraphQL s'exécuter en exécutant les images correspondantes du menu fixe. Créez un fichier appelé docker-compose.yaml et collez-y ce contenu.

Note : docker-compose est un utilitaire permettant d'exécuter plusieurs images de menu fixe. déclarativement.

 version: '2'
prestations de service:
  calendrier:
    image: timescale / timescaledb: latest-pg10
    redémarrer: toujours
    environnement:
      POSTGRES_PASSWORD: postgrespassword
    volumes:
    - db_data: / var / lib / postgresql / data
  graphql-engine:
    image: hasura / graphql-engine: v1.0.0-alpha38
    ports:
    - "8080: 8080"
    dépend de:
    - "échelle de temps"
    redémarrer: toujours
    environnement:
      HASURA_GRAPHQL_DATABASE_URL: postgres: // postgres: postgrespassword @ timescale: 5432 / postgres
      HASURA_GRAPHQL_ACCESS_KEY: mylongsecretkey
    commander:
      - moteur graphique
      - servir
      - --enable-console
volumes:
  db_data:

Ce docker-compose.yaml contient les spécifications de deux services:

  1. timescale
    Ceci est notre base de données Postgres avec l'extension Timescale installée. Il est configuré pour fonctionner sur le port 5432.
  2. graphql-engine
    Voici notre instance Hasura GraphQL Engine, c'est-à-dire le serveur GraphQL qui pointe vers la base de données et transmet les API GraphQL par dessus. Il est configuré pour s'exécuter sur le port 8080 et le port 8080 est mappé sur le port 8080 de la machine sur laquelle ce conteneur de menu fixe est exécuté. Cela signifie que vous pouvez accéder à ce serveur GraphQL via localhost: 8080 de la machine.

Lançons ces conteneurs de menu fixe en exécutant la commande suivante où que vous ayez placé votre fichier docker-compose.yaml . .

 docker-compose up -d

Cette commande extrait les images du menu fixe du nuage et les exécute dans l'ordre donné. Cela peut prendre quelques secondes en fonction de votre vitesse Internet. Une fois l’opération terminée, vous pouvez accéder à votre console GraphQL Engine à partir de http: // localhost: 8080 / console .

 Console Hasura GraphQL Engine
Console Hasura GraphQL Engine ( Grand aperçu )

Configuration de la base de données

Créons ensuite un tableau appelé temperature qui stocke les valeurs de température à différents moments. Accédez à l'onglet Données de la console et accédez à la section SQL . Créez notre table temperature en exécutant ce bloc SQL:

 CREATE TABLE temperature (
  température numérique non nulle,
  texte de localisation non nul,
  registered_at timestamptz non null default maintenant ()
)

Ceci crée une table Postgres simple dans la base de données. Mais nous souhaitons tirer parti du partitionnement d'intervalle de temps de l'extension Timescale. Pour ce faire, nous devons convertir cette table en hypertable de timescale en exécutant la commande SQL:

 SELECT create_hypertable ('temperature', 'registered_at');

Cette commande crée une hypertable qui est partitionnée par le temps dans le champ registered_at .

Maintenant, puisque cette table est créée, nous pouvons directement commencer à faire des requêtes GraphQL par dessus. Vous pouvez les essayer en cliquant sur l'onglet GraphiQL en haut. Essayez d'abord de créer une mutation:

 mutation {
  insert_temperature (
    objets: [{
      temperature: 13.4
      location: "London"
    }]
  ) {
    retournant {
      enregistré_at
      Température
    }
  }
}

La mutation GraphQL ci-dessus insère une ligne dans le tableau temperature . Essayez maintenant de faire une requête GraphQL pour vérifier si les données ont été insérées.

Puis essayez de faire une requête:

 query {
  Température {
    enregistré_at
    Température
    emplacement
  }
}

J'espère que cela a fonctionné:)

Nous avons maintenant pour tâche de créer un graphique en temps réel qui présente la température maximale d'un lieu par intervalles de 5 secondes au cours des 20 dernières minutes. Créons une vue qui nous donne exactement ces données.

 CREATE VIEW last_20_min_temp AS (
  SELECT time_bucket ('5 secondes', record_at) AS five_sec_interval,
  emplacement,
    MAX (température) AS max_temp
  De la température
  WHERE registered_at> NOW () - intervalle '20 minutes '
  GROUP BY five_sec_interval, emplacement
  ORDER BY five_sec_interval ASC
)

Cette vue regroupe les données du tableau température dans des fenêtres de 5 secondes avec leur température maximale ( max_temp) . Le regroupement secondaire est effectué à l'aide du champ location . Toutes ces données ne concernent que les vingt dernières minutes du moment présent.

Notre backend est mis en place. Construisons maintenant un joli graphique en temps réel.

Frontend

Bonjour les abonnements GraphQL

Les abonnements GraphQL sont essentiellement des requêtes GraphQL «réelles». Ils fonctionnent sur WebSockets et ont exactement la même structure de réponse que les requêtes GraphQL. Retournez à http: // localhost: 8080 / console et tentez de créer un abonnement GraphQL à la vue créée.

 subscription {
  last_20_min_temp (
    commandé par: {
      five_sec_interval: asc
    }
    où: {
      emplacement: {
        _eq: "Londres"
      }
    }
  ) {
    intervalle_sec
    emplacement
    max_temp
  }
}

Cet abonnement souscrit aux données de la vue dont le lieu est London et est classé dans l'ordre croissant de à cinq_second_intervals .

Bien entendu, la réponse de la vue serait un tableau vide car nous n’avons rien inséré dans la base de données au cours des vingt dernières minutes. (Vous pouvez voir l'entrée que nous avons insérée à un moment donné si vous atteignez cette section dans les vingt minutes.)

 {
  "Les données": {
    "last_20_min_temp": []
  }
}

En maintenant cet abonnement, ouvrez un autre onglet et essayez d'insérer une autre valeur dans le tableau températures en utilisant la même mutation que celle que nous avons effectuée précédemment. Après l'insertion, si vous revenez à l'onglet où se trouvait l'abonnement, la réponse se mettrait à jour automatiquement. C’est la magie en temps réel fournie par GraphQL Engine. Utilisons cet abonnement pour alimenter notre graphique en temps réel.

Mise en route de Create-React-App

Commençons rapidement avec un démarreur d’application React utilisant de créer une application réactive . Exécutez la commande suivante:

 npx create-react-app time-series-chart

Ceci créera un projet de démarrage vide. cd et installez les bibliothèques GraphQL et Chart. Aussi, installez moment pour convertir les horodatages en un format lisible par l'homme.

 cd-series-chart-series
npm installer --save apollo-boost apollo-link-ws abonnements-transport-ws graphql réagir-apollo chart.js réagir-chartjs-2 moment

Enfin, lancez l'application avec npm start et une application de base de React s'ouvrira à http: // localhost: 3000 .

 Raw create-react-app [19659036] Création-réaction-application brute (<a href= Grand aperçu )

Configuration du client Apollo pour GraphQL côté client

Le client Apollo est actuellement le meilleur client GraphQL qui fonctionne avec tout serveur compatible GraphQL. Relay modern est également utile, mais le serveur doit prendre en charge la spécification de relais afin de tirer parti de tous les avantages de Relay modern. Nous allons utiliser le client Apollo pour GraphQL côté client pour ce tutoriel. Exécutons la configuration pour fournir le client Apollo à l'application.

Je n'entre pas dans les subtilités de cette configuration car les extraits de code suivants sont extraits directement de la documentation . Allez dans src / index.js dans le répertoire de l'application React, instanciez le client Apollo et ajoutez l'extrait de code ci-dessus dans ReactDOM.render .

 import {WebSocketLink} de 'apollo-link -ws ';
importer {ApolloClient} de 'apollo-client';
importer {ApolloProvider} de 'react-apollo';
importer {InMemoryCache} de 'apollo-cache-inmemory';

// Créer un lien WebSocket:
const link = new WebSocketLink ({
  uri: 'ws: // localhost: 8080 / v1alpha1 / graphql',
  options: {
    reconnecter: true
  }
});
const cache = new InMemoryCache ();
const client = new ApolloClient ({
  lien,
  cache
});

Enfin, enveloppez App dans ApolloProvider afin que nous puissions utiliser le client Apollo dans les composants enfants. Votre App.js devrait enfin ressembler à:

 import Réagissez à partir de 'réagir';
importer ReactDOM de 'react-dom';
import './index.css';
importer l'application depuis './App';
importer {WebSocketLink} depuis 'apollo-link-ws';
importer {ApolloClient} de 'apollo-client';
importer {ApolloProvider} de 'react-apollo';
importer {InMemoryCache} de 'apollo-cache-inmemory';

// Créer un lien WebSocket:
const link = new WebSocketLink ({
  uri: `ws: // localhost: 8080 / v1alpha1 / graphql`,
  options: {
    reconnecter: true
  }
});
const cache = new InMemoryCache ();
const client = new ApolloClient ({
  lien,
  cache
});

ReactDOM.render (
  (
     
      
    
  ),
  document.getElementById ('root')
)

Le client Apollo a été configuré. Nous pouvons maintenant utiliser facilement GraphQL en temps réel à partir de notre application. Allez à src / App.js .

Création du graphique

ChartJS fournit une API très soignée pour la création de graphiques. Nous allons construire un graphique en courbes; donc un graphique en courbes attend des données de la forme:

 {
  "étiquettes": ["label1", "label2", "label3", "label4"],
  "jeux de données": [{
    "label": "Sample dataset",
    "data": [45, 23, 56, 55],
    "pointBackgroundColor": ["red", "brown", "green", "yellow"],
    "borderColor": "marron",
    "remplir": faux
  }],
}

Si le jeu de données ci-dessus est utilisé pour afficher un graphique à courbes, il se présenterait ainsi:

 Exemple de graphique à courbes
Exemple de graphique à courbes ( Grand aperçu )

Essayons pour construire cet exemple de graphique en premier. Importer Ligne de réagissez-chartjs-2 et transmettez-le en passant l'objet ci-dessus comme un accessoire de données. La méthode de rendu ressemblerait à quelque chose comme:

 render () {
  const data = {
    "étiquettes": ["label1", "label2", "label3", "label4"],
    "jeux de données": [{
      "label": "Sample dataset",
      "data": [45, 23, 56, 55],
      "pointBackgroundColor": ["red", "brown", "green", "yellow"],
      "borderColor": "marron",
      "remplir": faux
    }],
  }
  revenir (
    
); }

Nous allons ensuite nous abonner aux données de notre vue et les transmettre au graphique à courbes. Mais comment effectue-t-on des abonnements sur le client?

Le travail des composants d'Apollo utilisant le modèle rend prop où les enfants d'un composant sont rendus avec le contexte de l'abonnement données.


   {
    ({data, error, loading}) => {
      si (erreur) retourne ;
      si (chargement) retourne ;
      retour ;
    }
  }

Utilisons un de ces composants Subscription pour vous abonner à notre vue, puis transformez les données de souscription en une structure attendue par ChartJS. La logique de transformation ressemble à ceci:

 let chartJSData = {
  étiquettes: [],
  jeux de données: [{
    étiquette: "Température maximale toutes les cinq secondes",
    données: [],
    pointBackgroundColor: [],
    borderColor: 'marron',
    remplir: faux
  }]
};
data.last_20_min_temp.forEach ((item) => {
  const humanReadableTime = moment (item.five_sec_interval) .format ('LTS');
  chartJSData.labels.push (humanReadableTime);
  chartJSData.datasets [0] .data.push (item.max_temp);
  chartJSData.datasets [0] .pointBackgroundColor.push ('brown');
})

Note : Vous pouvez également utiliser la bibliothèque à code source ouvert graphq2chartjs pour transformer les données de la réponse GraphQL en un formulaire attendu par ChartJS.

. Après avoir utilisé cela à l'intérieur du composant Subscription, notre App.js ressemble à:

 import React, {Component} de 'react';
importer {ligne} de 'react-chartjs-2';
importer {Abonnement} de 'react-apollo';
importer le gql de 'graphql-tag';
importer le moment de 'moment';

const TWENTY_MIN_TEMP_SUBSCRIPTION = gql '
  abonnement {
    last_20_min_temp (
      commandé par: {
        five_sec_interval: asc
      }
      où: {
        emplacement: {
          _eq: "Londres"
        }
      }
    ) {
      intervalle_sec
      emplacement
      max_temp
    }
  }
'

La classe App étend le composant {
  render () {
    revenir (
      
{             ({data, error, loading}) => {               si (erreur) {                 console.error (erreur);                 retourne "Erreur";               }               si (chargement) {                 retour "Chargement";               }               laissez chartJSData = {                 étiquettes: [],                 jeux de données: [{                   étiquette: "Température maximale toutes les cinq secondes",                   données: [],                   pointBackgroundColor: [],                   borderColor: 'marron',                   remplir: faux                 }]               };               data.last_20_min_temp.forEach ((item) => {                 const humanReadableTime = moment (item.five_sec_interval) .format ('LTS');                 chartJSData.labels.push (humanReadableTime);                 chartJSData.datasets [0] .data.push (item.max_temp);                 chartJSData.datasets [0] .pointBackgroundColor.push ('brown');               })               revenir (                                )             }           }         
);   } } exportation par défaut App;

Vous aurez un graphique en temps réel pleinement opérationnel prêt à http: // localhost: 3000 . Cependant, il serait vide, alors peuplons quelques exemples de données pour que nous puissions voir un peu de magie se dérouler.

Note : J'ai ajouté quelques options supplémentaires au graphique à lignes parce que je n'en ai pas. t aime ces animations fantaisie dans ChartJS. Une série chronologique a l’air agréable quand elle est simple, cependant, vous pouvez supprimer les options si vous le souhaitez.

Insertion de données exemple

Permet d’écrire un script qui remplit notre base de données avec des données factices. Créez un répertoire séparé (en dehors de cette application) et créez un fichier appelé script.js avec le contenu suivant,

 const fetch = require ('node-fetch');
setInterval (
  () => {
    const randomTemp = (Math.random () * 5) + 10;
    chercher (
      `http: // localhost: 8080 / v1alpha1 / graphql`,
      {
        méthode: 'POST',
        body: JSON.stringify ({
          requête: `
            mutation ($ temp: numérique) {
              insert_temperature (
                objets: [{
                  temperature: $temp
                  location: "London"
                }]
              ) {
                retournant {
                  enregistré_at
                  Température
                }
              }
            }
          `,
          variables: {
            temp: randomTemp
          }
        })
      }
    ) .then ((resp) => resp.json (). then ((respObj) => console.log (JSON.stringify (respObj, null, 2))));
  },
  2000
)

Exécutez maintenant ces deux commandes:

 npm install --save node-fetch
noeud script.js

Vous pouvez revenir à http: // localhost: 3000 et voir la mise à jour du graphique.

Finishing Up

Vous pouvez créer la plupart des graphiques en temps réel à l'aide des idées que nous avons discuté ci-dessus. L'algorithme est le suivant:

  1. Déployez GraphQL Engine avec Postgres;
  2. Créez des tableaux dans lesquels vous souhaitez stocker des données;
  3. Abonnez-vous à ces tableaux à partir de votre application React;
  4. Rendez le graphique.

Vous pouvez trouver le code source ici .

 Editorial éclatant (dm, ra, il)




Source link