Utilisation des jointures dans les bases de données NoSQL MongoDB

 Utilisation delooklookUp avec NoSQL

Merci à Julian Motz d’avoir gentiment aidé à examiner cet article par les pairs.

L’une des plus grandes différences entre les bases de données SQL et NoSQL est la JOINTURE. Dans les bases de données relationnelles, la clause SQL JOIN vous permet de combiner des lignes de deux tables ou plus à l’aide d’un champ commun entre elles. Par exemple, si vous avez des tables de books et publishers, vous pouvez écrire des commandes SQL telles que:

SELECT book.title, publisher.nameFROM bookLEFT JOIN book.publisher_id ON publisher.id;

En d’autres termes, la table book a un champ publisher_id qui fait référence au champ id de la table publisher.

C’est pratique, car un seul éditeur pourrait proposer des milliers de livres. Si jamais nous avons besoin de mettre à jour les informations d’un éditeur, nous pouvons modifier un seul enregistrement. La redondance des données est minimisée, car nous n’avons pas besoin de répéter les informations de l’éditeur pour chaque livre. La technique est connue sous le nom de normalisation.

Les bases de données SQL offrent une gamme de fonctionnalités de normalisation et de contraintes pour garantir le maintien des relations.

NoSQL == Pas de JOINTURE ?

Pas toujours …

Les bases de données orientées document telles que MongoDB sont conçues pour stocker des données dénormalisées. Idéalement, il ne devrait y avoir aucune relation entre les collections. Si les mêmes données sont requises dans deux documents ou plus, elles doivent être répétées.

Cela peut être frustrant, car il y a peu de situations où vous n’avez jamais besoin de données relationnelles. Heureusement, MongoDB 3.2 introduit un nouvel opérateur $lookup qui peut effectuer une opération de type JOINTURE EXTERNE GAUCHE sur deux collections ou plus. Mais il y a un problème catch

L’agrégation MongoDB

$lookup n’est autorisée que dans les opérations d’agrégation. Considérez-les comme un pipeline d’opérateurs qui interrogent, filtrent et regroupent un résultat. La sortie d’un opérateur est utilisée comme entrée pour le suivant.L’agrégation

est plus difficile à comprendre que les requêtes find plus simples et s’exécutera généralement plus lentement. Cependant, ils sont puissants et une option inestimable pour les opérations de recherche complexes.L’agrégation

est mieux expliquée avec un exemple. Supposons que nous créions une plate-forme de médias sociaux avec une collection user. Il stocke les informations de chaque utilisateur dans des documents séparés. Par exemple:

{ "_id": ObjectID("45b83bda421238c76f5c1969"), "name": "User One", "email: "[email protected]", "country": "UK", "dob": ISODate("1999-09-13T00:00:00.000Z")}

Nous pouvons ajouter autant de champs que nécessaire, mais tous les documents MongoDB nécessitent un champ _id qui a une valeur unique. Le _id est similaire à une clé primaire SQL et sera inséré automatiquement si nécessaire.

Notre réseau social nécessite désormais une collection post, qui stocke de nombreuses mises à jour perspicaces des utilisateurs. Les documents stockent le texte, la date, une note et une référence à l’utilisateur qui l’a écrit dans un champ user_id:

{ "_id": ObjectID("17c9812acff9ac0bba018cc1"), "user_id": ObjectID("45b83bda421238c76f5c1969"), "date: ISODate("2016-09-05T03:05:00.123Z"), "text": "My life story so far", "rating": "important"}

Nous voulons maintenant afficher les vingt derniers messages avec une note « importante » de tous les utilisateurs dans l’ordre chronologique inverse. Chaque document retourné doit contenir le texte, l’heure de la publication et le nom et le pays de l’utilisateur associé.

La requête d’agrégat MongoDB reçoit un tableau d’opérateurs de pipeline qui définissent chaque opération dans l’ordre. Tout d’abord, nous devons extraire tous les documents de la collection post qui ont la note correcte en utilisant le filtre $match:

{ "$match": { "rating": "important" } }

Nous devons maintenant trier les éléments correspondants dans l’ordre inverse des dates à l’aide de l’opérateur $sort:

{ "$sort": { "date": -1 } }

Comme nous n’avons besoin que de vingt publications, nous pouvons appliquer une étape $limit, donc MongoDB n’a besoin que de traiter les données que nous voulons:

{ "$limit": 20 }

Nous pouvons désormais joindre les données de la collection user à l’aide du nouvel opérateur $lookup. Il nécessite un objet avec quatre paramètres:

  • localField: le champ de recherche dans le document d’entrée
  • from: la collection à rejoindre
  • foreignField: le champ à rechercher dans la collection from
  • as: nom du champ de sortie.

Notre opérateur est donc:

{ "$lookup": { "localField": "user_id", "from": "user", "foreignField": "_id", "as": "userinfo"} }

Cela créera un nouveau champ dans notre sortie nommé userinfo. Il contient un tableau où chaque valeur correspond au document user:

"userinfo": 

Nous avons une relation individuelle entre les post.user_id et user._id, car un article ne peut avoir qu’un seul auteur. Par conséquent, notre tableau userinfo ne contiendra qu’un seul élément. Nous pouvons utiliser l’opérateur $unwind pour le déconstruire en un sous-document:

{ "$unwind": "$userinfo" }

La sortie va maintenant être convertie dans un format plus pratique qui peut faire appliquer d’autres opérateurs:

"userinfo": { "name": "User One", "email: "[email protected]", …}

Enfin, nous pouvons renvoyer le texte, l’heure de la publication, le nom de l’utilisateur et le pays en utilisant une étape $project dans le pipeline:

{ "$project": { "text": 1, "date": 1, "userinfo.name": 1, "userinfo.country": 1} }

En regroupant le tout

Notre requête agrégée finale correspond aux publications, trie dans l’ordre, limite aux vingt derniers éléments, joint les données utilisateur, aplatit le tableau utilisateur et renvoie uniquement les champs nécessaires. La commande complète:

db.post.aggregate();

Le résultat est une collection de jusqu’à vingt documents. Exemple:

Super! Je Peux Enfin Passer à NoSQL !

MongoDB $lookup est utile et puissant, mais même cet exemple de base nécessite une requête agrégée complexe. Ce n’est pas un substitut à la clause de JOINTURE plus puissante proposée dans SQL. MongoDB n’offre pas non plus de contraintes ; si un document user est supprimé, les documents orphelins post resteraient.

Idéalement, l’opérateur $lookup devrait être requis rarement. Si vous en avez beaucoup besoin, vous utilisez peut-être le mauvais magasin de données …

Si vous avez des données relationnelles, utilisez une base de données relationnelle (SQL) !

Cela dit, $lookup est un ajout bienvenu à MongoDB 3.2. Il peut surmonter certains des problèmes les plus frustrants lors de l’utilisation de petites quantités de données relationnelles dans une base de données NoSQL.

You might also like

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.