Lorsque l'on a déjà beaucoup utilisé le langage SQL, on est familiarisé avec les jointures ( LEFT JOIN, INNER JOIN, …. ).
Mais une fois dans MongoDB comment faire de même ? Pour cela les agrégations vous permettrons de faire la même chose et bien plus encore.
Comment faire un INNER JOIN ?
Nous allons partir du principe que nous avons 2 Collections dans notre base.
- Contenu : qui nous permet de référencer différents types d'objets (marque, fournisseur, categorie, …),
- Produit : dans lequel nous avons comme lien la "marque" avec la collection Contenu
A présent, nous rechercherons les produits pour lesquels il n'y a pas de :
[{ $match: { $expr: { $eq: [ '$type', 'marque' ] } } }, { $lookup: { from: 'Produit', localField: '_id', foreignField: 'marque.$id', as: 'result' } }, { $match: { $expr: { $eq: [ '$result', [] ] } } }]
Utilisation d'un Pipeline
Il peu arriver comme dans mon cas que la quantité de données a traité est trop importante et que la requête avec un $lookup puis un $match ne fonctionne. Dans mon cas j'ai enregistré 40000 dans la collection Contenu et 350000 dans la collection Produit.
Cas ce cas il y a malgré toute une solution. En SQL cela reviendrait à utiliser des procédures stockées, ou tout simplement à devoir écrire du code avec un autre langage afin de scinder le traitement.
Mais avec MongoDB il existe les Pipeline. Un pipeline dans une agrégation est constitué d'une ou plusieurs étapes qui nécessitent les documents : Chaque étape effectue une opération sur les documents d'entrée. Par exemple, une étape peut filtrer des documents, regrouper des documents et calculer des valeurs. Les documents qui sortent d'une étape sont transmis à l'étape suivante.
Voici ce que cela donne dans notre cas :
[{ $match: { $expr: { $eq: [ '$type', 'marque' ] } } }, { $lookup: { from: 'Produit', 'let': { marque_id: '$marque.$id' }, as: 'result', pipeline: [ { $match: { $expr: { $eq: [ '$_id', '$$marque_id' ] } } }, { $match: { $expr: { $eq: [ '$result', [] ] } } } ] } }]
Exemple avec 2 conditions, l'une sur le type et l'autre du titre
[{ $match: { $expr: { $and: [ { $eq: [ '$type', 'marque' ] }, { $eq: [ '$titre', 'La marque' ] } ] } } }, { $lookup: { from: 'Produit', localField: '_id', foreignField: 'marque.$id', as: 'result' } }, { $match: { $expr: { $eq: [ '$result', [] ] } } }]).forEach( function(doc){}) db.Contenu.aggregate([{ $match: { $expr: { $and: [ { $eq: [ '$type', 'marque' ] }, { $eq: [ '$titre', 'Fizan' ] } ] } } }, { $lookup: { from: 'Produit', localField: '_id', foreignField: 'marque.$id', as: 'result' } }, { $match: { $expr: { $eq: [ '$result', [] ] } } }]