Les facets sont très utilisés sur les sites marchand pour le filtrage dynamique. Par exemple sur un site hôtelier, en cliquant sur Prix de 50€ A 100€ dans la barre de gauche, le contenu est rafraîchit en ne laissant que les hôtels correspondant à cette tranche de prix.

Pour ceux qui ne connaissent pas les facets, vous en trouverez une définition sur Wikipedia

Cette possibilité ne fonctionne qu’à partir de MongoDB 3.4.

Les exemples dans ce document, sont réalisés avec Python 3.4.3 et Pymongo 3.4.0 sous Windows

L’agrégation standard de MongoDB pouvait fournir un résultat assez proche mais avec beaucoup de difficultés et en moins performant.

Le nom donné par MongoDB à cette technique est le bucket.

Il en existe deux:

  • Le bucket manuel pour lequel vous définissez les tranches
  • Le bucket auto qui génére dynamiquement les tranches en fonction des résultats

Dans cette première partie, nous ne traiteront que du bucket manuel

Pour garder l’exemple de l’hôtel, vous avez une collection hotels dont chaque entrée dispose d’un champs numérique price.

Vous souhaitez obtenir des tranches de prix avec le nombre d’hôtels concernés par chaque tranche.

Avec un bucket manuel, vous définissez vous-même les tranches. Exemple [0, 50, 100, 200]

[{hotel_name: "Hotel du pont", price: 50},
{hotel_name: "Hotel de la rue", price: 70},
{hotel_name: "Hotel du coin", price: 45},
{hotel_name: "Hotel de la plage", price: 100}]

Définition et exécution de la requête:

>>> from pymongo import MongoClient
>>> db = MongoClient().aggregation_example
>>> facets = [
...   {
...     "$bucket": {
...       "groupBy": "$price",
...       "boundaries": [0, 50, 100, 200],
...       "default": "Other",
...       "output": {
...         "count": { "$sum": 1 },
...         "titles" : { "$push": "$hotel_name" }
...       }
...     }
...   }
... ]
>>> list(db.hotels.aggregate([{"$facet": facets}]))

Le paramètre "titles" : { "$push": "$hotel_name" } est optionnel mais permet de récupérer aussi la liste des hôtels de chaque tranche.

Le résultat retourné devrait ressembler à ça:

[{
  "_id" : 0,
  "count" : 1,
  "titles" : [
    "Hotel du coin"
  ]
},
{
  "_id" : 50,
  "count" : 2,
  "titles" : [
    "Hotel du pont",
    "Hotel de la rue"
  ]
},
{
  "_id" : 100,
  "count" : 1,
  "titles" : [
    "Hotel de la plage"
  ]
}]

J’ai réalisé ces exemples sans les essayer alors n’hésitez pas à ajouter un commentaire si vous trouvez une erreur.

Vous pouvez utiliser plusieurs bucket dans la même requête ainsi que d’autres options qui feront l’objet d’un autre article.

Documentation de référence:

  • https://docs.mongodb.com/manual/reference/operator/aggregation/bucket/
  • https://docs.mongodb.com/manual/reference/operator/aggregation/bucketAuto/

Stéphane RAULT


Commentaires

comments powered by Disqus