MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Le moyen le plus efficace de stocker des catégories imbriquées (ou des données hiérarchiques) dans Mongo ?

La première chose que vous voulez décider est exactement quel type d'arbre vous allez utiliser.

La grande chose à considérer est vos données et vos modèles d'accès. Vous avez déjà déclaré que 90 % de tout votre travail consistera en des requêtes et, à ce qu'il semble, les mises à jour (e-commerce) ne seront gérées que par les administrateurs, très probablement rarement.

Vous voulez donc un schéma qui vous donne le pouvoir d'interroger rapidement l'enfant à travers un chemin, c'est-à-dire :Sports -> Basketball -> Hommes, Sports -> Tennis -> Femmes, et n'a pas vraiment besoin de s'adapter aux mises à jour.

Comme vous l'avez si justement souligné, MongoDB a une bonne page de documentation pour cela :https://docs.mongodb.com/manual/applications/data-models-tree-structures/ dans lequel 10gen énonce en fait différents modèles et méthodes de schéma pour les arbres et décrit les principaux hauts et bas de ceux-ci.

Celui qui devrait attirer l'attention si vous cherchez à interroger facilement est les chemins matérialisés :https://docs.mongodb.com/manual/tutorial/model-tree-structures-with-materialized-paths/

C'est une méthode très intéressante pour construire des arbres puisque pour interroger sur l'exemple que vous avez donné ci-dessus dans "Femmes" dans "Tennis" vous pouvez simplement faire une regex pré-fixée (qui peut utiliser l'index :http://docs.mongodb.org/manual/reference/operator/regex/ ) comme ceci :

db.products.find({category: /^Sports,Tennis,Womens[,]/})

pour trouver tous les produits répertoriés sous un certain chemin de votre arbre.

Malheureusement, ce modèle est vraiment mauvais pour la mise à jour, si vous déplacez une catégorie ou changez son nom, vous devez mettre à jour tous les produits et il pourrait y avoir des milliers de produits dans une catégorie.

Une meilleure méthode serait d'héberger un cat_id sur le produit puis séparez les catégories dans une collection séparée avec le schéma :

{
    _id: ObjectId(),
    name: 'Women\'s',
    path: 'Sports,Tennis,Womens',
    normed_name: 'all_special_chars_and_spaces_and_case_senstive_letters_taken_out_like_this'
}

Alors maintenant, vos requêtes n'impliquent que la collection de catégories, ce qui devrait les rendre beaucoup plus petites et plus performantes. L'exception à cela est que lorsque vous supprimez une catégorie, les produits devront toujours être touchés.

Donc un exemple de changement de "Tennis" en "Badmin":

db.categories.update({path:/^Sports,Tennis[,]/}).forEach(function(doc){
    doc.path = doc.path.replace(/,Tennis/, ",Badmin");
    db.categories.save(doc);
});

Malheureusement, MongoDB ne fournit pas de réflexion de document dans la requête pour le moment, vous devez donc les retirer côté client, ce qui est un peu ennuyeux, mais j'espère que cela ne devrait pas entraîner le retour d'un trop grand nombre de catégories.

Et c'est essentiellement comme ça que ça marche vraiment. C'est un peu pénible à mettre à jour, mais le pouvoir de pouvoir interroger instantanément sur n'importe quel chemin à l'aide d'un index est plus adapté à votre scénario, je pense.

Bien sûr, l'avantage supplémentaire est que ce schéma est compatible avec les modèles d'ensembles imbriqués :http://en.wikipedia .org/wiki/Nested_set_model que j'ai trouvé maintes et maintes fois sont tout simplement géniaux pour les sites de commerce électronique, par exemple, Tennis peut être à la fois sous "Sports" et "Loisirs" et vous voulez plusieurs chemins en fonction de l'origine de l'utilisateur.

Le schéma des chemins matérialisés le prend facilement en charge en ajoutant simplement un autre path , c'est simple.

J'espère que ça a du sens, c'est assez long.