Mis à jour le mercredi 4 janvier 2017
  • 1 heure
  • Moyenne
Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Introduction du cours

Appréhender le moteur de base de données MongoDb 

Présentation rapide de MongoDb 

 MongoDb est un système de base de données dans la mouvance NoSQL. Il est orienté documents. Son nom vient de Humongous qui veut dire énorme ou immense. L'objectif est donc de pouvoir gérer de grandes quantités de données. Comment ? Le moteur de base de données facilite l'extension (on parle de scaling) si bien que l'on pourra supporter l'accroissement de la quantité de données par l'ajout de machines.

Orienté documents, qu'est ce que cela signifie?

 Dans un système de base de données relationnelles, les informations sont stockées par ligne dans des tables. Ces tables sont mises en relation en utilisants des clés primaires et étrangères. 

Par exemple, prenons une base de données qui contient des Acteurs et des Films  :

Table Acteur:

id

nom 

 prenom

 1

Johansson 

Scarlett 

2

Phoenix

Joaquim

Table Film:

id

titre

1

Her

2

Avengers

Table de jointure Acteur_Film qui permet d'associer les acteurs qui ont joué un rôle dans un film:

film_id

acteur_id

1

1

1

2

2

1

 L'information est rangée dans des tables et si l'on souhaite récupérer le casting d'un film, il faut faire une requête SQL avec des jointures pour récupérer les bonnes lignes des tables.

 Dans MongoDb, l'information est modélisée sur un document au format JSON (Javascript Object Notation). Je détaillerai dans la suite du cours ce format. Pour vous donner un aperçu, cela peut donner pour notre exemple 2 documents:

{_id: "Her", acteurs : [{nom:"Johansson", prenom:"Scarlett"}, {nom:"Phoenix", prenom:"Joaquim"}]}
{_id: "Avengers", acteurs : [{nom:"Johansson", prenom:"Scarlett"}]}

 Ici pas de jointure pour récupérer le casting d'un film, il suffit de lire le document qui nous intéresse.

 Ceux qui viennent du monde des bases de données relationnelles sont peut être choqués de voir que les acteurs sont dupliqués. Dans le monde NoSQL, on n'hésite pas à dénormaliser le schéma de la base de données pour favoriser les performances à la lecture.  L'important est de savoir quelles requêtes seront faites pour décider du format des documents.

Installer MongoDb

 Avant d'entrer dans le vif du sujet, vous allez devoir installer mongodb.Vous pouvez trouver MongoDb en téléchargement ici:

http://www.mongodb.org/downloads

Une fois que vous avez récupéré l'archive de MongoDb qui correspond à votre OS, vous devez trouver 2 fichiers:

  • mongod(.exe)

  • mongo(.exe)

mongod sert à démarrer le moteur de base de données tandis que mongo est un interpréteur de commandes. 

 Ouvrez un premier invite de commande pour lancer le moteur de base de données:

 mongod

 Si le démarrage est réussi, vous devez voir que le processus se lance sur le port 27017 qui est le port par défaut utilisé par MongoDb.

Un message comme celui-ci vous l'indique:

waiting for connections on port 27017

Puis ouvrez un second invite de commande pour lancer l'intrepréteur de commandes :

 mongo

Vous êtes maintenant connecté à votre moteur de base de données.

Première insertion de données

Format des données

Le format JSON (JavaScript Object Notation) est utilisé pour l'insertion et la restitution des documents.  

Connaissez vous le format JSON?

Ce format se base sur 2 types d'éléments:

  • la paire clé/valeur, par exemple "nom": "Phoenix"

  • le tableau, par exemple "couleurs-primaires" : ["cyan", "jaune", "magenta"]

Un objet contient donc des paires clés/valeurs et ou des tableaux séparés par des virgules.

{"nom": "Phoenix", "prenom" : "Joaquim", 
       "couleurs_preferees" : ["vert", "marron"]}

Sachant que la valeur d'une paire clé/valeur peut être un objet et que le tableau peut contenir des objets, on peut ordonner les informations sur plusieurs niveaux:

{"acteur": { "nom": "Phoenix", "prenom" : "Joaquim" }, 
  "roles" : [ 
             {"personnage" : "Theodore", "film" : "her"}, 
             {"personnage" : "Leonard Kraditor","film" : "Two Lovers "} 
            ] 
}

 

 Les documents ne sont pas directement stockés dans la base de données en JSON mais dans un format binaire appelé BSON.

 Dans les exemples ci-dessus, il n'y a que des chaines de caractères. D'autres types sont supportés: les booléens, les nombres et null.

Avec MongoDb on a en plus les date avec ISODate que je ne détaillerai pas dans ce cours. 

Ajout d'un document

Maintenant que l'interprêteur de commandes est démarré, nous allons insérer un premier document. 

 Il nous faut en premier lieu une base de données, appelons là openclassrooms.  Pour créer cette base de données, il suffit de dire à MongoDb que l'on souhaite l'utiliser et comme elle n'existe pas, il va la créer tout seul:

use openclassrooms

 Dans une base de données relationnelle on crée des tables pour y mettre nos données. Dans mongodb, notre base de données contient des collections dans lesquelles on ajoute nos documents. Une collection est donc un ensemble de documents de même nature.

  Nous allons créer une collections d'acteurs. La création de la collection est implicite, elle se fait à l'insertion du premier document.

Pour insérer un premier acteur nous allons utiliser la commande suivante

db.acteurs.insert({nom:"Johansson", prenom:"Scarlett"}) 

La commande se décompose comme ceci:

                       db.<nom de la collection>.insert( <document> )

Nous avons donné pour nom de la collection : acteurs

Le document que nous avons inséré est le suivant :

{nom: "Johansson", prenom: "Scarlett"}

Maintenant nous pouvons vérifier que notre donnée est bien insérée:

db.acteurs.find() 

MongoDb vous retourne ce que contient la base de données:

{ "_id" : ObjectId("532b3d9affed85e92a692432"), "nom" : "Johansson", "prenom" : "Scarlett" }

 On retrouve donc notre document avec en plus la propriété "_id" qui est un identifiant unique pour le document. S'il n'est pas spécifié à l'insertion, MongoDb génère un unique ObjectId qui identifie le document.

MongoDb est schemaless, ce qui signifie que les documents ne doivent pas tous respecter le même format.

Si vous utilisez la commande suivante:

db.acteurs.insert({nom:"E.T.", terrien:false}) 

 L'insertion est acceptée alors que les 2 documents n'ont en commun que la propriété nom.

Cela est très utile lorsque vous démarrez sur un nouveau projet. Souvent au début la base de données évolue beaucoup et ça nécessite alors de faire des modifications du schéma. 

Néanmoins pour que ce soit maintenable, il faut que votre collection contienne des documents de même type (n'allez pas mélanger des acteurs et des listes de course dans la même collection). Il faut créer des collections différentes si ce n'est pas le cas.  

 

Faire une recherche

Paramètres de la méthode find

Critères de recherche

Suite à notre insertion, nous avons pu récupérer notre document en utilisant la méthode find().

Cette méthode renvoie tout ce qu'il y a dans la base de données. Elle n'est donc pas utilisable sur une collection qui contient beaucoup de documents. 

Nous allons en créer une. Nous allons l'appeler produits. Pour cela nous allons profiter du fait que l'interpréteur de commandes supporte le javascript et insérer 100 000 documents :

for(i=1; i<=100000; i++){var dixmill = i%10000; var mill = i%1000; var cent = i%100; db.produits.insert({compteur:i, dixmill:dixmill, mill:mill, cent:cent })}

Maintenant si vous faites:

db.produits.find() 

Vous verrez une première page de résultats apparaître, si vous voulez consulter le 100 000ième document, il vous faudra taper la commande it un grand nombre de fois.

La méthode find prend pour premier paramètre un objet JSON qu'elle va prendre comme critère de recherche.

Si par exemple vous faites

 db.produits.find({dixmill:9999})

Vous allez avoir tous les documents qui correspondent à dixmill = 99999.

En SQL, cela revient à faire une requête avec une clause where.

On peut préciser notre critère de recherche en ajoutant une autre valeur :

 db.produits.find({compteur:19999, dixmill:9999})

A vous maintenant, que faut il écrire pour récupérer les documents qui ont pour valeur cent = 89 et mill = 289

Si vous avez réussi vous devez avoir 100 résultats. Pour connaitre le nombre de résultats, vous pouvez appeler la méthode count() après la méthode find(). Par exemple db.produit.find({dixmill:9999}).count().

On peut aller plus loin sur le critère de recherches en ajoutant des opérandes :

  • $gt : plus grand que

  • $lt : plus petit que

  • $gte : plus grand ou égal à

  • $lte: plus petit ou égal à

  • $or : pour récupérer les documents qui correspondent à 2 critères différents

  • $and : pour cumuler des critères

  • $in, $all, $exist, $type et $regex ...

Un exemple: 

si vous faites la requête suivante:

db.produits.find({dixmill: {$gte:9997, $lt:9999 }})

Vous allez récupérer tous les documents ou dixmill est inférieur à 9999 et supérieur ou égal à 9997.

Récupérez tous les produits qui ont pour leur valeur mill supérieure ou égale à 525 et la valeur cent inférieure à 90

Si vous avez réussi, vous devez avoir 42500 résultats (en utilisant la méthode count()).

Vous savez maintenant faire une recherche simple. Nous allons voir comment filtrer les résultats.

Filtrer les résultats

 Pour le moment, lorsque nous faisons une requête, nous récupérer les documents dans leur ensemble. Si les documents sont volumineux, il peut être intéressant de ne récupérer que les valeurs qui nous intéressent. 

La méthode find() prend un deuxième paramètre qui va nous servir à récupérer les propriétés qui nous intéressent.

Si vous faites :

db.produits.find({dixmill: 525} , {compteur:1})

 Dans les résultats, vous n'avez plus que _id et compteur dans vos résultats. Compteur est renvoyé parce que dans le second paramètre, vous l'avez listé avec la valeur 1. _id est systématique renvoyé.

Si vous ne voulez pas récupérer _id, il faut explicitement le mettre à 0

db.produits.find({dixmill: 525} , {_id:0, compteur:1})

Trier les résultats

 Pour trier les résultats, nous pouvons utiliser la méthode sort().

Par exemple, si vous faites l'opération suivante:

db.produits.find({mill : {$in: [500, 600, 700]}})

Vous voyez que mill vaut alternativement 500, 600 et 700. 

Maintenant si on trie de manière croissante sur mill

db.produits.find({mill : {$in: [500, 600, 700]}}).sort({mill:1})

 Vous constatez qu'en premier lieu vous n'avez que les documents dont la valeur mill vaut 500. Si vous tapez la commande it plusieurs fois, vous allez arrivez aux documents ou mill vaut 600 puis 700.

Pour trier dans l'autre sens :

db.produits.find({mill : {$in: [500, 600, 700]}}).sort({mill:-1})

En mettant -1 on trie de manière décroissante.

Faire une mise à jour

Ajout/Modification d'une propriété

Pour faire la mise à jour d'un ou plusieurs documents, il faut utiliser la méthode update().

Comme pour la méthode find(), le premier paramètre sert de critère de recherche pour les documents à mettre à jour, le second va servir à définir la mise à jour voulue.

Par exemple, si vous faites:

db.produits.update({dixmill: 666} , {$set : {suspicieux:true}})

Ensuite faites :

db.produits.find({dixmill:666})

Vous constatez que le document avec pour compteur 666 a été mis à jour mais pas les suivants. Pourquoi? MongoDb ne met à jour que le premier document qu'il trouve avec le critère donné. Si vous voulez tous les mettre à jour, il faut lui dire avec la commande suivante:

db.produits.update({dixmill: 666} , {$set : {suspicieux:true}}, {multi:true})

On indique avec le paramètre multi que l'on souhaite mettre à jour tous les documents trouvés.

On peut modifier la valeur que l'on a ajouté:

db.produits.update({dixmill: 666} , {$set : {suspicieux:"why?"}}, {multi:true})

Vous pouvez maintenant constater en recherchant les documents avec pour valeur dixmill = 666 que le champ suspicieux vaut "why?"

Suppression d'une propriété

Nous allons supprimer la propriété que l'on vient d'ajouter. Pour cela, nous allons utiliser $unset.

db.produits.update({dixmill: 666} , {$unset : {suspicieux:1}}, {multi:true})

Ici nous indiquons que nous voulons supprimer la propriété suspicieux ajoutée au préalable.

Mise à jour d'un tableau

On va ajouter un tableau à un document

db.produits.insert({compteur:100001, tab:['a','b','c']})

Vous pouvez le consulter avec la commande suivante:

db.produits.find({compteur:100001})

Maintenant pour ajouter un élément, on utilise l'opérande $push:

db.produits.update({compteur:100001}, {$push : {tab : 'd'}})

Si vous consultez à nouveau ce document vous constatez que le tableau tab contient:

[ "a", "b", "c", "d" ]

Pour en ajouter plusieurs d'un coup, il existe $pushAll pour ajouter un tableau de valeur.

Avec l'opérande $pop on va supprimer le dernier élément:

db.produits.update({compteur:100001}, {$pop : {tab:1}})

Le tableau a perdu son dernier élément "d".

Pour supprimer le premier élément:

db.produits.update({compteur:100001}, {$pop : {tab:-1}})

De façon analogue avec la méthode sort, en mettant -1 on supprime les éléments dans l'autre sens.

Avec l'opérande $addToSet, on ajoute sans doublon :

db.produits.update({compteur:100001}, {$addToSet : {tab : 'b'}})

La valeur "b" était présente dans le tableau donc il n'y pas eu d'ajout.

Supprimer un document

La suppression d'un document se fait grâce à la méthode remove.

Par exemple:

db.produits.remove({mill: 600})

Supprime tous les documents qui ont pour pour valeur 600 à la propriété mill.

Conclusion

Ce cours qui vous donne un premier éclairage sur MongoDb est terminé, merci de l'avoir suivi, j'espère qu'il vous permettra de démarrer sur l'utilisation de mongodb.

Exemple de certificat de réussite
Exemple de certificat de réussite