2012-08-07 6 views
0

J'ai une collection de balises, elles ont seulement une valeur qui est l'étiquette. Ils peuvent être balise aléatoire ou une balise d'arbre (ici un échantillon sans _id):Requêtes imbriquées avec express/mongoose

{ 
    "label": "/test1" 
} 
{ 
    "label": "/test2" 
} 
{ 
    "label": "/test1/test1-1" 
} 
{ 
    "label": "/test2/test2-1" 
} 
{ 
    "label": "/test1/test1-1/test1-1-1" 
} 
{ 
    "label": "something" 
} 

Ce que je veux est d'avoir un seul objet avec l'arbre de mes tags:

{ 
    "/test1": { 
     "name": "test1" 
     , "children": { 
      "/test1/test1-1" : { 
       "name": "test1-1" 
       , "children": { 
        "/test1/test1-1/test1-1-1" : { 
         "name": "test1-1-1" 
         , "children": {} 
        } 
       } 
      } 
     } 
    } 
    , "/test2": { 
     "name": "test2" 
     , "children": { 
      "/test2/test1-2" : { 
       "name": "test1-2" 
       , "children": {} 
      } 
     } 
    } 
} 

Voici ce que j'ai essayé dans mon application:

app.get('/tree', function(req, res, next) { 
    var tree = {}; 
    Tag 
    // If you have a better solution, I'm not really fan of this 
    .$where('this.label.split(new RegExp("/")).length === 2') 
    .exec(function(err, tags) { 
     tags.forEach(function(tag) { 
      tag.getChildren(function(children) { 
       tree[tag.label] = { 
        'title': tag.label 
        , 'children': children 
       } 
      }); 
     }); 
    }); 
    // do some stuff with the `tree` var 
    // which does not work because of the asynchronousity of mongo 
}); 

Et dans mon modèle, je l'ai, il ne fonctionne pas, au début, je voulais retourner le chemin de l'arbre avec avec tag.getChildren() mais, je pensais un rappel sera une meilleure option et je m'arrête là.

Tag.methods.getChildren = function(callback) { 
    var tree = {}; 
    Tag 
    .$where('this.label.split(new RegExp("' + this.label + '/")).length === 2') 
    .exec(function(err, tags) { 
     tags.forEach(function(tag) { 
      tag.getChildren(function(children) { 
       tree[tag.label] = { 
        'title': tag.label 
        , 'children': children 
       } 
      }); 
     }); 
     return tree 
    }); 
}; 

Je ne sais pas comment cela, je suis assez nouveau à nœud et programmation asynchrone de sorte que toute aide sera apprécié.

Répondre

1

Faire une demande multiple est stupide Mongo cet exemple, donc je ne seul, analyser le résultat et créer mon arbre, voici mon code si quelqu'un a le même problème:

app.get('/tree', function(req, res, next) { 
    var tree = {} 
    Tag 
    .find({ label: { $regex: /^\// } }, ['label']) 
    // Skip the "/" 
    .skip(1) 
    .exec(function(err, tags) { 
     tags.forEach(function(tag) { 
      var split = tag.label.split('/'); 
      // Root 
      if (split.length === 2) { 
       tree[_.slugify(split[1])] = { 
        title: split[1] 
        , children: {} 
       } 
      } else { 
       var name = split.pop() 
        , path = tag.label 
        , pathSlug = _.slugify(path.replace(/\//g, '-')) 
        , parentPath = path.split('/') 
        , parentSlug = '' 
        , parent; 
       parentPath.shift(); 
       parentPath.pop(); 
       parentPath.forEach(function(step) { 
        step = parentSlug ? parentSlug + '-' + _.slugify(step) : _.slugify(step); 
        parentSlug = step; 
        parent = parent ? parent.children[step] : tree[step]; 
       }); 
       if (!parent) { 
console.error('ERROR :') 
console.log(tag.label) 
console.log(path.split('/')) 
console.log(name) 
console.error('##################') 
       } else { 
        parent.children[pathSlug] = { 
         title: name 
         , children: {} 
        } 
       } 
      } 
     }); 
     res.send(tree, 200); 
    }); 
}); 
1

Vous devriez probablement regarder dans le module async.js, qui a un certain support pour faire une itération qui appelle le code asynchrone à chaque étape et exécuter un rappel lorsque tout le code asynchrone est fait.

Questions connexes