Sridhar Nanjundeswaran nous fait une excellente présentation de MongoDB : bien technique sachant que nous étions tous des développeurs à l’écoute, mais en même temps suffisamment transverse pour qu’on puisse trouver des points de compréhension facilement.
La partie importante de NoSQL est surtout que la donnée n’est pas relationnelle, ce qui permet d’obtenir une scalabilité horizontale plus forte. L’idée principale de MongoDB est d’évoluer librement et de faire du sharding pour améliorer la performance en écriture, alors qu’en mode relationnel, on a plutôt tendance à dégrader la structure normalisée et à gérer des problèmes de cohérence de cache ou de partitionnement logique pour améliorer la performance.
MongoDB est un système basé sur un master unique. MongoDB laisse l’OS se charger du cache d’écriture, car il utilise des fichiers mappés en mémoire. En MongoDB, une ligne est en fait un document JSON (en fait, la persistance est réalisée en BSON – Binary JSON) qui suit la description d’un schéma. Du coup, un Join peut être un embedded document, ou bien un identifiant vers un autre document.
http://try.mogodb.org permet de tester le système sans avoir à l’installer. Sinon, en local, on dézippe le contenu téléchargé, et on lance mongod.exe, en lui laissant prendre le défaut sur /data/db. En démarrant, il crée une console web pour les premières opérations de gestion. mondo.exe est un client simple. show dbs pour voir la liste des bases de données disponibles, et il y aura au minimum une base de données de test. db.posts.insert(p) avec p créé en écriture JSON pour faire notre première écriture. La fenêtre, au passage, est un vrai shell complet (SpiderMonkey), donc on peut faire des calculs, etc.
dp.posts.find() va faire un FindAll pour vérifier que les lignes ont été insérées, ce qu’on peut également vérifier par la présence d’un premier fichier de persistance de 64 Mo. La ligne a automatiquement ajouté un _id, qui est globalement unique, si il n’existait pas. Si on tape db.posts.findOne sans parenthèses, on a la définition de la fonction à titre d’aide. show collections donne accès à la liste des bases, en l’occurrence dans nos exemples depuis le début, posts.
db.stats() et dp.help() ou db.posts.help() donnent des informations sur le contenu et l’aide sur les commandes globales ou les commandes sur les collections. En MongoDB (contrairement à un SGBD où toutes les colonnes sont forcées sur toutes les lignes par la simple existence du schéma), il y a une différence entre la présence d’un attribut et sa présence avec une valeur null. Du coup, c’est l’opérateur $exists qui permet de voir ceci.
Attention, si on fait un $set, on remplace la totalité du contenu de l’attribut, alors que $push va rajouter une valeur dans un tableau. $unset enlève complètement le champ, ce qui est différent de pousser la valeur null dedans. En MongoDB, un update s’applique seulement sur le premier document qui correspond au critère. Il faut mettre le flag multi pour avoir le comportement comme dans une base de données.
Une relation 1-n peut être modélisée avec plus ou moins de force dans MongoDB, ce qui permet de prendre en compte le métier, où certains objets sont liés de manière forte (suppression automatique des fils sur la suppression du parent, etc.), mais certains ont un lien beaucoup plus lâche. On peut par exemple faire un arbre avec l’objet contenu dans le document du père. C’est très performant, mais plus compliqué si on doit récupérer une partie seulement du document. Surtout, il y a une limite de 16 Mo sur la taille d’un document unique. Sinon, on peut faire des liens en utilisant les identifiants des parents et des enfants. La table des ancêtres est alors elle-même indexée.
L’indexation est très puissante en MongoDB : on peut par exemple créer un index sur un attribut d’un document, mais aussi un attribut multi-clé sur les entrées d’un attribut contenant une table de valeurs. Enfin, il y a également un index basé sur la géolocalisation. Les index peuvent être incomplets, et du coup, il n’y aura pas de ressource perdue si un document ne contient pas l’attribut sur lequel on travaille.
Il est essentiel d’utiliser du 64 bits, car MongoDB utilise des fichiers mappés en mémoire, et du coup, on se retrouve limité à 1,5 Go environ si on est en 32 bits.
Le fournisseur .NET permet de piloter la sérialisation de telle ou telle manière pour un objet donné. La chaîne de connexion est de type “mongodb://localhost”. Le fait d’utiliser une base ou une collection est suffisant pour la créer si elle n’existe pas. En .NET, on va typiquement faire un insert sur une instance de BsonDocument.
MongoDB sur Azure existe, et fait appel aux mêmes librairies que la version serveur. Il est possible d’utiliser un worker role sur Azure pour mettre en place un MongoDB. En Azure, le mode d’installation est automatiquement avec un replica set.
Une question me reste à trouver : quelle est la relation de MongoDB à Map/Reduce ? MongoDB permet de faire du clustering pour la répartition des données, et il semble que du coup, comme le sharding se fait automatiquement, les requêtes soient naturellement parallélisées.
MongoDB utilise un niveau de lock sur les fichiers mappés en mémoire, ce qui lui permet de ne pas bloquer des ensembles complets. La structure étant très peu hiérarchisée par rapport à une base de données, c’est pratique car on peut locker non pas au niveau d’un métier, ce qui est en général gênant, mais plutôt au niveau d’une entité de l’infrastructure, en l’occurrence l’atome de stockage.