Tutoriel

Installer la base de données

[Téléchargez] la base de données, décompressez la et démarrez le démon mongd :

$ bin/mongod 

Récupérer une connexion à la base de données

Essayons maintenant de manipuler la base à partir du shell (Nous pourrions effectuer les mêmes opérations à partir de n'importe quel langage de développement en utilisant le driver approprié. Le shell est cependant plus pratique pour une utilisation interactive).
Démarrez le shell javascript de MongoDB de la façon suivante :

$ bin/mongo 

(Par défaut le shell se connecte à une base implicite sur l'hôte local). Vous devriez voir :

MongoDB shell version: 0.9.8 
url: test 
connecting to: test 
type "help" for help 
> 

"connecting to:" donne le nom de la base utilisée par le shell. Pour basculer sur une autre base, tapez :

> use mydb 


Pour afficher la liste des principales commandes, saisir help.

Astuce pour les développeurs ayant une expérience sur d'autres bases de données

Vous pourrez noter dans les exemples ci-dessous que nous ne créons jamais de base de données ou de collections. MongoDB ne l'impose pas. Dès que vous insérer quelque chose, MongoDB créé la collection ou la base sous-jacente. Si vous exécutez une requête sur une collection qui n'existe pas, Mongo considère que la collection est vide.

Insérer des données dans une collection

Créons une collection test et insérons des données. Nous allons créer 2 objets j et t, et allons les sauver dans la collection things.
Dans les exemples suivants, '>' indique des commandes saisies au prompt du shell.

> j = { name: "mongo"}; 
{"name" : "mongo"} 
> t = { x : 3 }; 
{ "x" : 3 } 
> db.things.save(j); 
> db.things.save(t); 
> db.things.find(); 
in cursor for : DBQuery: example.things -> 
{"name" : "mongo" , "_id" : "497cf60751712cf7758fbdbb"} 
{"x" : 3 , "_id" : "497cf61651712cf7758fbdbc"} 
> 


Quelques elements à noter :

  • Nous n'avons définit aucune collection. La base de données la créé automatiquement lors de la première insertion.
  • Les documents que nous insérons peuvent avoir n'importe quelle "structure" – en fait dans cet exemple, les documents n'ont aucun element de données en commun. En pratique, les documents de structures équivalent sont insérés dans une même collection. En pratique, cette flexibilité permet de réaliser facilement des migrations ou des évolutions de schémas – vous aurez rarement besoin de scripts pour réaliser des opérations de type "alter table".
  • Avant d'être insérés dans la base, les objets se voient assigné un identifiant (s'ils n'en ont pas déjà un) dans le champs _id.
  • Quand vous exécutez l'exemple ci-dessus, les valeurs de ObjectID seront différentes.

Ajoutons quelques enregistrements supplémentaires dans cette collection :

> for( var i = 1; i < 10; i++ ) db.things.save( { x:4, j:i } );
> db.things.find(); 
in cursor for : DBQuery: example.things -> 
{"name" : "mongo" , "_id" : "497cf60751712cf7758fbdbb"} 
{"x" : 3 , "_id" : "497cf61651712cf7758fbdbc"} 
{"x" : 4 , "j" : 1 , "_id" : "497cf87151712cf7758fbdbd"} 
{"x" : 4 , "j" : 2 , "_id" : "497cf87151712cf7758fbdbe"} 
{"x" : 4 , "j" : 3 , "_id" : "497cf87151712cf7758fbdbf"} 
{"x" : 4 , "j" : 4 , "_id" : "497cf87151712cf7758fbdc0"} 
{"x" : 4 , "j" : 5 , "_id" : "497cf87151712cf7758fbdc1"} 
{"x" : 4 , "j" : 6 , "_id" : "497cf87151712cf7758fbdc2"} 
{"x" : 4 , "j" : 7 , "_id" : "497cf87151712cf7758fbdc3"} 
{"x" : 4 , "j" : 8 , "_id" : "497cf87151712cf7758fbdc4"} 
has more 

Notez que tous les documents ne sont pas affichés – le shell en limite le nombre à 10 quand il parcourt un curseur. Etant donné que nous avons déjà 2 documents dans la collection, nous voyons seulement les 8 premiers éléments nouvellement insérés.
Si nous voulons voir la suite des resultats, nous pouvons utiliser le raccourci it. Ci-dessous la suite du code précédent :

{"x" : 4 , "j" : 7 , "_id" : "497cf87151712cf7758fbdc3"} 
{"x" : 4 , "j" : 8 , "_id" : "497cf87151712cf7758fbdc4"} 
has more 
> it 
{"x" : 4 , "j" : 9 , "_id" : "497cf87151712cf7758fbdc5"} 
{"x" : 4 , "j" : 10 , "_id" : "497cf87151712cf7758fbdc6"} 

Techniquement, find() retourne un objet de type curseur. Cependant dans les précédents cas, nous n'avons affecté ce curseur à aucune variable. De ce fait, le shell parcourt automatiquement le curseur, nous présentant les premiers résultats et nous offrant la possibiltié de continuer l'itération à l'aide de la commande it. Mais il est possible de travailler directement avec le curseur, comme cela est présenté dans la prochaine section.

Accéder aux données à partir d'une requête

Avant d'aborder plus en detail le sujet des requêtes, nous allons présenter la manière de travailler avec le résultat d'une requête – l'objet curseur. Nous utiliserons la méthode find() qui retourne tout le contenu d'une collection, et parlerons de la manière de créer des requêtes spécifiques plus tard.
Pour voir tous les éléments contenus dans une collection à partir du [shell mongo], nous devons impérativement utiliser le curseur retourner par l'opération find().
Répétons la même requête que précédemment, mais cette fois utilisons le curseur retourné par la méthode afin d'itérer sur celui dans une boucle :

> var cursor = db.things.find(); 
> while (cursor.hasNext()) { print(tojson(cursor.next())); } 
{"name" : "mongo" , "_id" : "497cf60751712cf7758fbdbb"} 
{"x" : 3 , "_id" : "497cf61651712cf7758fbdbc"} 
{"x" : 4 , "j" : 1 , "_id" : "497cf87151712cf7758fbdbd"} 
{"x" : 4 , "j" : 2 , "_id" : "497cf87151712cf7758fbdbe"} 
{"x" : 4 , "j" : 3 , "_id" : "497cf87151712cf7758fbdbf"} 
{"x" : 4 , "j" : 4 , "_id" : "497cf87151712cf7758fbdc0"} 
{"x" : 4 , "j" : 5 , "_id" : "497cf87151712cf7758fbdc1"} 
{"x" : 4 , "j" : 6 , "_id" : "497cf87151712cf7758fbdc2"} 
{"x" : 4 , "j" : 7 , "_id" : "497cf87151712cf7758fbdc3"} 
{"x" : 4 , "j" : 8 , "_id" : "497cf87151712cf7758fbdc4"} 
{"x" : 4 , "j" : 9 , "_id" : "497cf87151712cf7758fbdc5"} 
> 

Le code précédent montre une itération utilisant un curseur. La méthode hasNext() permet de savoir si il y a d'autres documents à retourner, et la méthode next() retourne le prochain document. Nous utilisons également la méthode interne tojson() permettant d'afficher le résultat dans un format JSON plus agréable à lire.
Lorsque nous travaillons en Javascript à partir du [shell], nous pouvons utiliser toutes les fonctionnalités du langage, et par exemple appeler la méthode forEach sur le curseur. Le code précédent devient alors :

> db.things.find().forEach( function(x) { print(tojson(x));}); 
{"name" : "mongo" , "_id" : "497cf60751712cf7758fbdbb"} 
{"x" : 3 , "_id" : "497cf61651712cf7758fbdbc"} 
{"x" : 4 , "j" : 1 , "_id" : "497cf87151712cf7758fbdbd"} 
{"x" : 4 , "j" : 2 , "_id" : "497cf87151712cf7758fbdbe"} 
{"x" : 4 , "j" : 3 , "_id" : "497cf87151712cf7758fbdbf"} 
{"x" : 4 , "j" : 4 , "_id" : "497cf87151712cf7758fbdc0"} 
{"x" : 4 , "j" : 5 , "_id" : "497cf87151712cf7758fbdc1"} 
{"x" : 4 , "j" : 6 , "_id" : "497cf87151712cf7758fbdc2"} 
{"x" : 4 , "j" : 7 , "_id" : "497cf87151712cf7758fbdc3"} 
{"x" : 4 , "j" : 8 , "_id" : "497cf87151712cf7758fbdc4"} 
{"x" : 4 , "j" : 9 , "_id" : "497cf87151712cf7758fbdc5"} 
> 

L'utilisation de forEach() impose la definition d'une function qui est appelée pour chaque document retourné par le curseur.
Depuis le [shell mongo] vous pouvez également considérer le curseur comme un tableau :

> var cursor = db.things.find(); 
> print (tojson(cursor[4])); 
{"x" : 4 , "j" : 3 , "_id" : "497cf87151712cf7758fbdbf"} 

Lorsque vous utilisez un curseur de cette façon, tous les éléments jusqu'à l'index accédé (cursor[4] dans notre exemple) sont montés en mémoire. C'est inapproprié pour de larges resultsets qui risquent de saturer la mémoire. Les curseurs doivent être utilisés dès lors que les requêtes retournent un nombre élevé d'éléments.
En plus de l'accès à un curseur orienté tableau, il est également possible de convertir le curseur en un véritable tableau :

> var arr = db.things.find().toArray(); 
> arr[5]; 
{"x" : 4 , "j" : 4 , "_id" : "497cf87151712cf7758fbdc0"} 

Toutefois cette possibilité est spécifique au [shell mongo], et n'est pas porposée par tous les drivers.
Les crurseurs MongoDB ne sont pas des snapshots – les opérations réalisées sur la collection en train d'être parcourue par un curseur peuvent ou non être prises en compte dans les résultats retournés par le curseur. Utilisez un verrouillage explicite pour exécuter une requête en mode snapshot.

Paramétrer le résultat des requêtes

Maintenant que nous savons comment manipuler les curseurs, regardons de près comment paramétrer les requêtes pour retourner des données spécifiques.
En générale on utilise les documents de requête (query document) qui sont des documents contenant les couples clés/valeurs qui doivent être vérifiés.
Dans les exemples suivants nous allons, à partir de quelques requêtes SQL, montrer comment les représenter en utilisant le [shell mongo]. Cette manière de spécifier les requêtes est fondamentale dans MongoDB et aurez le possibilité de réaliser la même chose avec n'importe quel langage ou driver.

SELECT * FROM things WHERE name="mongo"
> db.things.find({name:"mongo"}).forEach(function(x) { print(tojson(x));}); 
{"name" : "mongo" , "_id" : "497cf60751712cf7758fbdbb"} 
> 
SELECT * FROM things WHERE x=4
> db.things.find({x:4}).forEach(function(x) { print(tojson(x));}); 
{"x" : 4 , "j" : 1 , "_id" : "497cf87151712cf7758fbdbd"} 
{"x" : 4 , "j" : 2 , "_id" : "497cf87151712cf7758fbdbe"} 
{"x" : 4 , "j" : 3 , "_id" : "497cf87151712cf7758fbdbf"} 
{"x" : 4 , "j" : 4 , "_id" : "497cf87151712cf7758fbdc0"} 
{"x" : 4 , "j" : 5 , "_id" : "497cf87151712cf7758fbdc1"} 
{"x" : 4 , "j" : 6 , "_id" : "497cf87151712cf7758fbdc2"} 
{"x" : 4 , "j" : 7 , "_id" : "497cf87151712cf7758fbdc3"} 
{"x" : 4 , "j" : 8 , "_id" : "497cf87151712cf7758fbdc4"} 
{"x" : 4 , "j" : 9 , "_id" : "497cf87151712cf7758fbdc5"} 
> 


Une expression de requêtes est elle-même un document. Un document de requête de la forme { a:A, b:B, ... } signifie "where a==A and b==B and ...". Vous trouverez plus d'information sur les requêtes dans la section Requêtes et curseurs du guide de développement Mongo .
MongoDB permet également de ne retourner que des documents « partiels », c'est-à-dire un sous-ensemble des éléments d'un document stocké dans la base. Pour ce faire, vous ajouter un second argument dans l'appel de la méthode find() contenant la liste des éléments à retourner.
Pour illustrer ce point, répétons le dernier exemple find({x:4}) en ajoutant un nouvel argument limitant le contenu des documents retournés au éléments "j" :

SELECT j FROM things WHERE x=4
> db.things.find({x:4}, {j:true}).forEach(function(x) { print(tojson(x));}); 
{"j" : 1 , "_id" : "497cf87151712cf7758fbdbd"} 
{"j" : 2 , "_id" : "497cf87151712cf7758fbdbe"} 
{"j" : 3 , "_id" : "497cf87151712cf7758fbdbf"} 
{"j" : 4 , "_id" : "497cf87151712cf7758fbdc0"} 
{"j" : 5 , "_id" : "497cf87151712cf7758fbdc1"} 
{"j" : 6 , "_id" : "497cf87151712cf7758fbdc2"} 
{"j" : 7 , "_id" : "497cf87151712cf7758fbdc3"} 
{"j" : 8 , "_id" : "497cf87151712cf7758fbdc4"} 
{"j" : 9 , "_id" : "497cf87151712cf7758fbdc5"} 
> 

Notez que le champ "_id" est systématiquement retourné.

findOne()

Le [shell mongo] vous permet d'éviter la gestion d'un curseur pour récupérer un seul enregistrement en utilisant la fonction findOne(). Cette méthode prend les mêmes paramètres que la fonction find() et ne retourne que le premier document correspondant à la requête, ou null si aucun document ne répond aux critères.
Récupérons par exemple le premier document avec le champs name=='mongo'. Il a plusieurs façon de faire, comme appeler la méthode next() sur le curseur (en vérifiant que ce dernier n'est pas null évidemment) ou considérer le curseur comme un tableau et récupérer l'élément d'index 0.
La fonction findOne() est à la fois efficace et pratique :

> var mongo = db.things.findOne({name:"mongo"}); 
> print(tojson(mongo)); 
{"name" : "mongo" , "_id" : "497cf60751712cf7758fbdbb"} 
> 

Cette méthode est particulièrement efficace puisque le client ne récupère qu'un objet de la base, donc permet de minimiser le travail de la base et le traffic réseau. C'est l'équivalent de l'appel find({name:"mongo"}).limit(1).

Limiter la taille du résultat via limit()

Vous pouvez limiter le nombre de résultats retournés par une requête en utilisant la méthode limit().
Cette méthode est fortement recommandée puisqu'elle permet de l'imiter le travail de la base de donénes et la quantité de données transitant sur le réseau. Par exemple :

> db.things.find().limit(3); 
in cursor for : DBQuery: example.things -> 
{"name" : "mongo" , "_id" : "497cf60751712cf7758fbdbb"} 
{"x" : 3 , "_id" : "497cf61651712cf7758fbdbc"} 
{"x" : 4 , "j" : 1 , "_id" : "497cf87151712cf7758fbdbd"} 
> 

What Next

La prochaine étape après la lecture de ce tutoriel est de parcourir le manuel pour entrer dans les détails.


Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.