Formation MongoDB M101N: semaine 1 – introduction

Quelques caractéristiques:
– “Rich documents”: on peut stocker davantages que de simples valeurs,
– “Prejoin” en utilisant des documents intégrés (embedded documents),
– Pas de jointures en MongoDB,
– Pas de contraintes,
– Pas de transactions,
– Pas de schéma conceptuel.

Le principe général d’une base MongoDB est d’avoir des schémas de données proches de l’application.

Les bases relationnelles sont conçues pour:
– Interdire de modifier la base en introduisant des anomalies,
– Minimise le redesign de la base quand le schéma conceptuel grossit,
– Il permet d’éviter d’être influencer par certains patterns d’accès.

MongoDB ne pousse pas à utiliser un pattern par rapport à un autre. Ensuite il faut éviter d’introduire des anomalies à la création de données.

Exemple d’articles d’un blog

Par exemple, pour afficher les articles d’un blog, on peut stocker tous les éléments de l’article:
– titre,
– auteur,
– contenu,
– date,
– mots clé.

Tous les commentaires:
– auteur du commentaire,
– email,
– contenu du commentaire.

Tous ces éléments peuvent être stockés dans la même collection en utilisant des documents intégrés (embedded document).

Si on utilise un schéma proche de celui qu’on aurait utilisé dans une base relationnelle, on aurait:
– une collection pour les articles avec un ID, titre, corps, auteur et date,
– une collection pour les commentaires avec un ID, un ID d’article (clé étrangère), auteur, adresse email et l’ordre d’affichage du commentaire,
– une collection pour les tags avec un ID, un tag et un ID d’article (clé étrangère).

Ce type de schéma impose de
– maintenir une relation entre les 3 collections en utilisant des clés étrangères,
– maintenir l’ordre dans la collection des commentaires,
– d’utiliser 3 fichiers sur le disque, 1 fichier par collection.
– d’accèder à 3 collections pour afficher un article.

Cette organisation est plus lourde que de considérer une collection pour stocker tous les éléments.

Contraintes

Un des avantages de la base relationnelle est de garantir d’avoir des données consistantes en utilisant des clés étrangères. MongoDB ne garantit pas d’avoir des clés étrangères consistantes.
Le fait d’utiliser des documents intégrés garantit que les documents sont liés entre eux: si tous les commentaires sont directement dans la collection d’articles, par construction ils appartiennent à l’article.

Transactions

Pas de transactions en MongoDB mais les opérations sont atomiques.
Quand on insère des documents dans une collection, ils ne seront visibles que si le document est ajouté entièrement. En revanche, l’ajout de plusieurs documents n’est pas atomiques.
Le fait d’utiliser des documents intégrés permet de garantir la consistance des données.

En utilisant MongoDB, il faut:
– être restrictif en utilisant des documents intégrés ce qui permet d’insérer des données de façon consistante.
– implémenter des “locks” au niveau software
– tolérer une inconsistance dans les données.

Relations entre les objets logiques

Relations un vers un

Par exemple un employé et un CV, un employé n’a qu’un CV.
On peut stocker les infos dans 2 collections:

Employee:
- _ID,
- Name,
- Resume_ID
Resume 
- _ID,
- Jobs: [] (array)
- Education: []

Ou alors on inclut le CV directement dans la collection "Employee" sous forme de document intégré.

Pas de restrictions pour les relations un vers un, il faut juste avoir en tête:
La fréquence d’accès aux données: si on accède très souvent au CV d’un employé ou si on accède seulement aux informations de l’employé.
La taille des éléments: les informations du CV seront peut être plus volumineuse que celles de l’employé lui-même.
La limite de 16mb d’un document intégré: un document intégré ne peut dépasser 16mb.

Relations un vers plusieurs

Par exemple, une ville et une personne. Une ville contient plusieurs personnes.

Plusieurs schémas sont possibles:
1ere solution:

City:
- name,
- area;
- people: [] (array)

Ce schéma n’est pas possible car il y a beaucoup trop de personnes pour une ville, le tableau serait trop grand.

2e solution:

People:
- name,
- city : { name; area; }

Le problème avec ce schéma est de multiplier les données relatives à la ville dans tous les documents des personnes.

3e solution: 2 collections:

People:
- name;
- city: "NYC"
City:
- _ID: "NYC" 
- area

La 3e solution est la meilleure puisqu’on ne duplique pas les informations.

La 1ère solution aurait pu être choisi si il n’y avait pas beaucoup de personnes.

Pour les relations un vers plusieurs, l’important est de savoir l’ordre de grandeur du plusieurs:
dans le cas d’un grand nombre: il faut considérer une collection différente
dans le cas d’un nombre pas très élevé: il est préférable de privilégier un document intégré.

Plusieurs vers plusieurs

Par exemple, des livres et des auteurs.
Dans ce cas, il y a peu de livres pour un auteur et inversement, il a peu d’auteurs pour un livre. Donc il peut considérer 2 collections:

Books:
- _ID, 
- title, 
- authors: [ author_ID ]
Author: 
- _ID 
- Author_name, 
- books: [ books_ID ]

On peut inclure des références vers les auteurs dans la collection livre dans un tableau.

On peut aussi inclure directement les livres dans la collection auteur mais la contrainte est pour les livres qui ont plusieurs auteurs.

Dans le cas d’étudiants et de professeurs:

Un professeur possède beaucoup d’étudiants, on peut utiliser des documents intégrés en incluant un tableau de professeur dans la collection d’étudiants. Ce schéma peut poser problème si des étudiants sont aussi des professeurs.

Index multi-clé

Permet d’utiliser des index pour des relations plusieurs vers plusieurs.

Si on considère 2 collections telles que:

Students: 
- _ID, 
- name, 
- teachers: [ teacher_ID ] (tableau de teacher ID)
Teachers: 
- _ID 
- name,

Si on veut lister les professeurs d’un étudiant, on peut le faire directement. En revanche, si on veut les étudiants d’un professeur, on aura besoin d’un index multi-clé.

db.students.ensureIndex({ 'teachers':1 })

Pour avoir tous les étudiants d’un professeur:

db.students.find({ 'teachers': { $all: [ 0, 1 ] } })

Pour savoir comment l’index est utilisé:

db.students.ensureIndex({ 'teachers':1 }).explain()

Avantages d’utiliser des documents intégrés

– Permet d’améliorer les performances en lecture
– Effectuer un seul aller-retour avec la base de données
La base utilise des disques durs dont le temps d’accès est long mais qui ont une bande passante élevée: on met du temps à attendre l’information mais on peut charger rapidement beaucoup d’information en même temps. Il est donc préférable d’avoir des informations rapprochées pour les charger d’un coup.

Arbres

Par exemple, si on considère des produits et des catégories. Les catégories appartiennent à d’autres categories.
On peut proposer ce schéma:

Products: 
- Category, 
- Product_name
Category: 
- _ID 
- Category_name 
- ancestors: [ category_ID ]

Ainsi tous les ascendants de la categorie se trouvent dans le tableau “ancestors”.

Si on veut les descendants d’un categorie, il suffit de faire:

db.category.find({ ancestors: 35 })

Leave a Reply