Découvrir la base NoSQL MongoDB

Les bases de données NoSQL ont fait leur apparition ces dernières années, pour répondre à un défaut des bases de données relationnelles : la scalabilité. Le volume de données à traiter est de plus en plus grand, et le temps de réponse, et donc de réactivité des applications, doit toujours être le même. Les bases de données non relationnelles permettent de répondre à ce besoin, en apportant quelques contraintes.

Ces bases ne répondent pas forcément au besoin de tous les projets et demandent une conception différente des modèles de données relationnelles.

MongoDB est un système de base de données orientée documents. C’est un système de stockage de collections de documents JSON, et il permet d’interroger la base via des requêtes en JavaScript. Ces documents ne possèdent pas de schéma, ils n’ont donc pas tous, les mêmes champs.

Introduction

Le but de cet article est de présenter l’approche différente que nécessite le choix d’utiliser la base MongoDB, ainsi que la manière différente d’écrire des requêtes pour obtenir les informations voulues.

Modélisation

Ce nouveau type de base de données amène des concepts qui sont différents des modèles relationnels, comme on peut le voir dans le tableau ci-dessous :

BDD Relationnelle MongoDB
Database Database
Table Collection
Row Document
Column Field
Table Join Embedded Documents
Primary Key Primary Key / Default Key

Une notion très importante dans les modèles relationnels a été supprimée : le système de jointure. Tout simplement parce que ce n’est pas scalable !

Une clé primaire unique doit être définie, si ce n’est pas le cas, une clé par défaut sera créée. Cette clé est une valeur hexadécimale basée sur plusieurs informations de la machine.

Il faut modéliser la base pour avoir une structuration orientée cas d’usage/d’accès. Il ne faut surtout pas avoir autant de collections que de tables dans un modèle relationnel. Pour un cas d’utilisation simple, on arrive très vite à modéliser 40 tables avec un modèle relationnel, alors qu’il faut généralement 3 ou 4 documents pour MongoDB.

Pour lier deux éléments, il faut concevoir la base de manière différente, avec des documents qui contiennent des sous-documents, en insérant en deuxième un élément qui ne peut pas exister sans le premier.

Un document peut faire au maximum 16 MB, on ne peut donc pas utiliser des sous-documents pour tous les cas d’utilisation. La deuxième solution sera de faire référence à la clé primaire d’une autre collection, dans un champ ordinaire sans contrainte.

Toutes les contraintes devront être traitées côté application.

Le principal problème de ne pas avoir de système de jointure est la duplication. Pour limiter ce phénomène, il est parfois intéressant d’utiliser une référence à une clé étrangère.

Suivant les cas d’usages, une solution sera plus appropriée que l’autre.

Les principaux cas étant :

  • One To Many -> clé étrangère (exemple : 1 ville -> plusieurs personnes)
  • One To Few -> document embarqué (exemple : 1 blog -> plusieurs commentaires)
  • Many To Many -> clé étrangère (exemple : des étudiants ont des professeurs)
  • Few To Few -> clé étrangère (exemple : des livres <-> des auteurs)

Pour résumé, il n’y a plus ni schéma ni contraintes d’intégrité, ce qui peut provoquer une duplication de données, et un risque d’incohérence des données. L’opération atomique est sur un document. Il faudra réaliser ces vérifications dans l’application, en utilisant les opérations atomiques et en tolérant un peu d’incohérence.

MongoDB vs BDD relationnelle

Maintenant que l’on connaît les principales différences entre ces deux bases de données, une question reste à aborder : quand est-il plus judicieux d’utiliser l’une ou l’autre ?

L’un des principaux intérêts de MongoDB est sa performance et sa scabilité. C’est la raison pour laquelle vous n’êtes pas sûr de vouloir utiliser une  BDD relationnelle classique qui a fait ses preuves, vous avez un gros volume de données à traiter, et une très  haute disponibilité est attendue. Ces performances sont assurées au détriment de la gestion de transactions complexes. Presque toutes les informations doivent se retrouver au sein du même document.

Exemple : Dans le cas d’un site internet qui gère des séries TV, MongoDB est tout indiqué. Une série a plusieurs saisons, puis chaque saison a plusieurs épisodes, et chaque épisode a plusieurs critiques et plusieurs acteurs. Quand les utilisateurs viennent sur le site, typiquement, ils vont sur la page en particulier d’une des séries TV. Sur cette page, ils voient toutes les saisons et tous les épisodes, avec toutes les critiques et tous les acteurs de cette série, le tout sur une seule page. Du point de vue de l’application, quand l’utilisateur visite la page d’une série, on veut récupérer toute l’information raccordée à cette série.

On ne va donc consulter qu’un seul document par série. Il existe des milliers de séries, le temps de réponse sera de plusieurs  secondes avec une BDD relationnelle, alors qu’il sera de moins d’1 seconde avec MongoDB.

MongoDB sera au contraire moins indiqué pour un réseau social, où on voudra savoir quels utilisateurs auront liker et/ou commenter un post d’un utilisateur. Chaque utilisateur étant unique, il faudra gérer des transactions entre une collection de documents utilisateurs uniques, et une collection de documents posts qui fera référence à ces utilisateurs. Cela aura des conséquences sur les performances.

Le second grand intérêt d’utiliser MongoDB est sa flexibilité. Il n’y a pas de schéma, donc vous pouvez rajouter des champs très facilement, c’est un point très important si vos données en entrée évoluent régulièrement.

Requêtes

C’est bon ! vous vous êtes décidé, MongoDB sera la solution utilisée. Mais comment fonctionne le système de requêtes ?

Pour pouvoir lancer des requêtes, il faut d’abord télécharger et installer Mongo DB.

Il faut ensuite ajouter le répertoire d’installation jusqu’au répertoire bin dans les variables d’environnement puis lancer la commande :

mongod –dbpath data –port 27017 –fork –smallfiles

Le serveur mongo stockera ces fichiers dans le répertoire data indiqué ci-dessus.

Bonne nouvelle, on peut déjà se connecter depuis une console avec cette simple commande :

mongo

Pour les plus allergiques à la ligne de commande, vous pouvez utiliser cette petite interface graphique Robomongo.

robomongo

Maintenant que l’environnement est installé (c’était plutôt rapide, nan ?!), on est prêt pour travailler.

Création / Recherche

Les requêtes utilisent des fonctions JavaScript, commençons en insérant des données :

db.macollection.insert( { “nom” : “Doe”,  “prenom” : “John” , “age” : 30 , “profession” : “developpeur”})

On passe donc le nom de notre collection, qui sera créée si elle n’existe pas, et les données à insérer avec le nom des champs sous forme de document JSON. Maintenant que des données sont insérées, on va vouloir les retrouver :

db.macollection.findOne(filtre,projection) -> renvoie un document

db.macollection.find(filtre,projection)  -> renvoie tous les documents

Le filtre est un document JSON correspondant à la clause WHERE en SQL. La projection est un document JSON correspondant à la clause SELECT en SQL. On sélectionne les champs à retourner, en indiquant les noms des champs comme clés avec une valeur booléenne, sans précision, tout le document est retourné.

db.macollection.findOne( { “nom” : “Doe”} , { “nom” : true}).pretty();

Dans le dernier exemple, on a rajouté une petite fonction pretty, qui permet d’indenter l’affichage. Il nous reste à utiliser les opérateurs de comparaison :

db.macollection.find( { “age” : { $gte : 18} }) ;    Toutes les personnes ayant au moins 18 ans

Les schémas n’existent plus, les documents sont donc non structurés, mais on peut vérifier  si un champ existe :

db.macollection.find( {profession : { $exists : true } });

On peut également réaliser d’autres opérations comme sort, skip, limit, count

db.macollection.find({ “age” : { $gte : 18} }).limit(10).skip(2) ;

Update

Pour terminer, il nous reste à voir comment mettre à jour les données. Pour cela, on va réaliser des update, on passera de la même manière des documents JSON pour la sélection et la mise à jour à réaliser :

db.macollection.update( query, update, option)

query : requête de sélection des documents

update : définition de l’action de remplacement

options :

  1. upsert : permet de créer si n’existe pas
  2. multi : traite plusieurs documents (par défaut, un update ne traite qu’un seul document)

Pour terminer, les tableaux étant un élément important du JavaScript, il existe également les fonctions d’agrégation qui vont permettre d’éclater des tableaux pour les grouper dans une requête, et ainsi avoir le résultat souhaité :

  • $group : groupement de données
  • $unwind : pour éclater les tableaux
  • $project : permet de fixer la projection
  • $match : permet de fixer les filtres

Les possibilités sont vastes et je vous invite à consulter la documentation officielle pour approfondir. Nous avons vu l’essentiel pour commencer mais il existe également les notions de réplication et de sharding qui permettent d’améliorer encore les performances.

Conclusion

Avec cette présentation rapide, j’espère vous avoir donné une meilleure idée des bases de données NoSQL et en particulier de MongoDB. La documentation officielle est bien fournie et la communauté des utilisateurs est très active. Il existe d’autres base de données NoSQL (Cassandra, Neo4j, Redis…) et je vous invite à les découvrir.

Leave a Reply

Your email address will not be published. Required fields are marked *