Skip to content

Utilisation de la base de données MongoDB dans Meteor

Posted on:12 mai 2017 at 02:00

Précédemment, nous avons vu comment faire en sorte que notre application Meteor devienne persistante via l’utilisation de Session. Ceci était un bon début mais, il existe un problème avec cette solution. Un petit malin pourrait très bien modifier les données sauvegarder dans les cookies ou vider son cache. Ce qui est assez embêtant.

La solution est donc de sauvegarder ses informations au niveau de notre serveur. De cette façon, elles seront protégées, ne seront jamais supprimées (sauf si on le demande). Et bonne nouvelle, Meteor nous permet de faire cela très simplement grâce à une base de données embarquée, du nom de MongoDB.

MongoDB c’est quoi ?

Avant d’attaquer en pur et dur le code, il serait bien de voir rapidement comment fonctionne MongoDB. À l’inverse d’une base de données SQL (comme Microsoft SQL ou MySQL), MongoDB ne fonctionne pas de la même manière.

Dans une base de données SQL, vous devez créer des tables, avec une structure bien définie et stricte. Vous devez donc suivre ce schéma défini précédemment à la lettre pour pouvoir inclure une ligne de données dans celle-ci. Malheureusement, cette façon de faire est maintenant un peu dépassée (je ne dis pas qu’il ne faut plus l’utiliser, mais il existe des alternatives) et les bases de données NoSQL font leur grande apparition.

Plus simplement, MongoDB ne possède pas, lui, de table prédéfinie. Une donnée peut être ajoutée “à la volée” avec un identifiant unique qui sera généré. Sans influencer, d’une quelconque manière, les enregistrements précédents. Vous comprendrez plus facilement cela par la suite. Pour les plus curieux, vous pouvez en apprendre plus sur le fonctionnement de MongoDB par ici.

Le code !

Bon, attaquons maintenant le code ! La façon dont nous allons utiliser MongoDB va être un tantinet simpliste. Nous l’utiliserons dans le futur différemment. Mais nous y reviendrons.

Les collections

La première étape va consister à créer une collection. Voilà l’explication officielle de Meteor :

Les collections sont la manière pour Meteor de stocker des données persistantes. La spécificité des collections dans Meteor est qu’elles peuvent être consultées à la fois par le serveur et le client, ce qui facilite l’écriture de la logique de vue sans avoir à écrire beaucoup de code au niveau du serveur. Ils se mettent également à jour eux-mêmes automatiquement, de sorte qu’un composant de vision supporté par une collection affichera automatiquement les données les plus récentes.

Vous l’aurez donc compris, une collection fait le lien entre Meteor et MongoDB. Nous avons vu précédemment qu’avec une base de données NoSQL comme Mongo, il n’existe pas de table, que chaque donné est stocké “à la volée”. Pour simplifier la structure de notre code, Meteor nous propose donc les collections, que l’on pourrait comparer à des tables virtuelles. Elles n’existent pas physiquement comme pour MySQL mais, sont simulées et gérer pour nous. Cela nous simplifiera donc grandement la tâche !

Passons au code, la première étape va être de créer un nouveau dossier du nom de “collections” à la racine de notre projet. Peu importe le nom de celui-ci, c’est à vous de voir. Pourquoi à la racine ? Simplement pour que le code que nous écrirons dedans soit accessible à la fois sur le client et serveur. Si vous voulez un rappel, je vous renvoie à cet article. Puis maintenant, créer un fichier du nom de counter.js dans ce dossier. Copier le code suivant dans celui-ci.

Counter = new Mongo.Collection("counter");

Nous créons donc ici une variable globale, qui sera à la fois accessible depuis le client et le serveur du nom de Counter. Par la suite nous lui assignons un nouvel objet du type Mongo (pour MongoDB) puis nous précisions que nous voulons créer une collection. Le paramètre demandé correspond à un identifiant pour cette collection, donc ici counter.

Cette simple ligne de code ne paraît pas, mais c’est grâce à elle que nous allons pouvoir par la suite ajouter des entrées et modifier la base de données.

Le serveur

Maintenant que nous avons le nécessaire pour faire le lien entre notre application et la base de données MongoDB,  il nous reste donc à configurer le côté serveur. Voilà les différentes choses que nous avons à faire :

Voilà donc les différentes étapes que nous allons devoir mettre en place. Et bonne nouvelle, Meteor nous permet de mettre en place ça très facilement et rapidement avec peu de code.

Startup

Commençons par le Startup. C’est ici que nous allons écrire le code qui créera la donnée dans MongoDB. Comme Counter est accessible à la fois sur le client et le serveur nous pouvons y accéder depuis le serveur. Nous vérifions donc simplement, via la condition, si une ligne existe déjà. Si non, alors nous la créons.

Meteor.startup(() => {
    // Créer un Counter si aucun n'existe
    if (Counter.find().count() === 0) {
        // Ajoute une ligne dans la base de données
        Counter.insert({ value:0 });
    }
});

Comme vous pouvez le voir, la méthode insert permet d’insérer une ligne dans la base de données. Entre les parenthèses  nous pouvons énumérer les différentes variables que nous souhaitons enregistrer. Mais, vous allez vous dire, l’on ne devrait pas définir les différentes variables et le type de ses variables lors de la création de la Collection ? Comme pour du MySQL par exemple ?

Eh bien non, comme nous l’avons vu, les tables n’existent pas en MongoDB, elles sont seulement virtuelles. Par conséquent, plusieurs lignes d’une même collection peuvent avoir des données différentes, d’un même nom mais d’un type différent. Par exemple, le code suivant fonctionne sans problème :

Counter.insert({ value:0 });
Counter.insert({ value:0.6, number:9 }); // Ici un double puis un entier
Counter.insert({ value:"Une chaîne de caractère" });

La collection est donc la même mais, les données sont très différentes. Cela ne pose aucun problème. C’est ce qui fait la flexibilité de MongoDB et sa puissance. Avec une base de données SQL traditionnel cela serait impensable et surtout irréalisable.

Création d’un Publish

Comme je l’ai expliqué précédemment, l’instruction Publish va nous permettre de choisir ce que l’on souhaite envoyer au client comme information, l’on peut vouloir seulement envoyer le prénom de l’utilisateur par exemple. De plus, un Publish ne peut retourner qu’une seule collection. Cela signifie que plus vous aurez de collection, plus vous devrez en déclarer (si vous souhaitez transiter les données vers le client).

Meteor.publish('counter', function() {
    return Counter.find();
});

Le premier paramètre est le nom que nous allons donner, un identifiant pour se Publish (nous en auront besoin côté client) puis, nous retournons la liste des données contenues dans la collection Counter de MongoDB. Ici, sans rien spécifier de plus dans les parenthèses de find, toutes les données seront envoyées au client.

Création d’une méthode

La dernière étape au niveau du serveur va être de créer une méthode. Cette méthode sera appelée depuis le client et nous permettra d’augmenter le compteur. Car, seul le serveur a le droit d’écrire et de modifier la base de données, pour des raisons de sécurité.

Meteor.methods({
    'increaseCounter':function(id) {
        // Augmente de 1 la valeur 'value'
        Counter.update(id, {
            $inc: { value:1 }
        });
    }
});

C’est ici que nous déclarons des méthodes côté serveur. Comme vous pouvez le voir, nous lui donnons en premier lieu un identifiant, un nom. Puis, par la suite, nous créons une fonction avec un paramètre, ici l’identifiant d’une ligne MongoDB, notre compteur. La méthode update va nous permettre de mettre à jour les données de cette ligne. Le premier paramètre correspond à l’identifiant, pour que notre collection sache quelle ligne mettre à jour puis, par la suite, le mot-clef $inc signifie incrémenté. Entre les crochets nous indiquons que l’on souhaite modifier la colonne value et ajouter 1.

Ce bout de code aura donc pour effet d’augmenter la valeur de notre compteur de +1 !

Le client

Maintenant que notre collection, notre base de données et que notre serveur est bon, il ne nous reste plus que le client ! Mais cette fois-ci les changements vont être mineurs et la logique va être la même. Pas de modification au niveau de Blaze, du HTML pour le moment. Les modifications à venir sont donc au niveau du main.js, dans le dossier client.

Cette fois-ci je vais donner le code en entier du fichier. La logique n’est pas du tout modifier, vous n’allez pas être perdu

import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';

import './main.html';

Template.hello.onCreated(function helloOnCreated() {
    Meteor.subscribe("counter");
});

Template.hello.helpers({
    counter() {
        // On récupère la première ligne de la collection Counter
        return Counter.findOne().value;
    }
});

Template.hello.events({
    'click button'(event, instance) {
        // On fait une une demande au serveur pour qu'il incrémente la valeur
        Meteor.call('increaseCounter', Counter.findOne()._id);
    }
});

Meteor.subscribe permet d’indiquer que l’on souhaite écouter le Publish du nom de counter que nous avons créé précédemment au niveau du serveur. Grâce à cette ligne de code, nous allons pouvoir récupérer la liste des données stockées dans cette collection, dans tout le template hello.

Dans le helpers, grâce au subscribe que nous avons appelé lors de la création du template, la variable Counter, qui correspond à la variable globale que nous avons créée plus tôt dans cet article avec la collection, contient maintenant la liste des données qui sont dans la base de données.

Nous utilisons findOne car nous voulons récupérer la première ligne (il n’en existe de toute façon qu’une seule, que nous créons dans le Startup du serveur) puis, le .value nous permet de choisir la donnée que va contenir la variable counter de Blaze. Ce qui aura donc pour effet d’afficher cette valeur dans notre rendu HTML pour l’utilisateur. Pour ceux qui auraient oublié le fonctionnement de Blaze je vous renvoie à cet article.

Parlons maintenant de Meteor.call(). Cette instruction nous permet d’exécuter une méthode qui se trouve sur le serveur, qui a lui les autorisations de modifier la base de données.  Le premier paramètre est donc l’identifiant de cette méthode, le second paramètre correspond à un paramètre que nous lui envoyons. Ici, comme dans le helpers, nous récupérons le premier élément de la collection Counter mais cette fois nous utilisons son identifiant. Celui-ci est généré aléatoirement par Meteor lors de l’insertion d’une donnée. Il faut donc utiliser ._id pour le récupérer. Le _ nous indique simplement que cette variable n’est pas créée par nous mais, par MongoDB. La méthode sera donc appelée et le compteur augmenter de +1.

MeteorMongoApp

Si vous démarrez votre application (pour rappel avec la commande Meteor dans votre invité de commandes) avec les nouvelles modifications et cliquer sur le bouton, son comportement sera identique à avant. Si vous rechargez votre page, la valeur sera donc toujours la même comme avec les Sessions. Sauf que, ouvrer deux pages de votre navigateur côte à côte et cliqué sur le bouton. Magie !! Le compteur augmente des deux côtés ! La valeur du compteur est stockée dans la base de données et comme c’est le serveur qui s’en occupe et qu’il n’existe qu’un seul serveur, le compteur est donc le même pour tous ! Il pourrait y avoir 3-4 personnes voir plus, chaque utilisateur verra le chiffre augmenté instantanément en temps réel. Meteor s’occupe pour nous de mettre à jour l’affichage de tous les utilisateurs.

À titre indicatif, si vous souhaitez réinitialiser la base de données MongoDB du projet, il vous suffit de faire la commande Meteor reset dans votre invité de commandes.