我有一个带有id的简单树,它是Mongo集合的关键。我正在使用名为treewalker的节点库。当我走遍树的每个节点时,我试图查找名称(使用mongoose)并简单地将其附加到当前节点。如果我不进行回调查找节点名称,只使用一些固定值,我会得到我期待的值。让我在代码中说明:
这是我的树:
{
"categoryTree": [
{
"categoryId": "1",
"children": [
{
"categoryId": "2",
"children": [
{
"categoryId": "3",
"children": []
},
{
"categoryId": "4",
"children": []
}
]
},
{
"categoryId": "5",
"children": []
},
{
"categoryId": "6",
"children": []
}
]
},
{
"categoryId": "7",
"children": [
{
"categoryId": "8",
"children": []
}
]
}
]
}
这是执行我想要的代码:
catTree.categoryTree.forEach(function(node){
var counter = 0;
tree.walkTree(node, 'children', function(obj){
obj.name = counter++;
});
});
//This tree has the names (as the counter above) in it as I expect
console.log(JSON.stringify(catTree));
但是,只要我输入一个mongoose回调来获取类别名称,打印的类别树就不再具有名称。
catTree.categoryTree.forEach(function(node){
tree.walkTree(node, 'children', function(obj){
//Cat is a mongoose model defined elsewhere
Cat.findById(obj.categoryId, {_id:0,name:1}).exec(function(err, value){
obj.name = value.name;
});
});
});
//This tree has NO names :(
console.log(JSON.stringify(catTree));
我知道这是一个时间问题,但我无法弄清楚如何解决它。我已经看过几篇SO文章like this one,建议跟踪回调,并且只有在他们被调用之后才会继续。我无法弄清楚如何将这种模式应用到我的案例中,因为我走了一棵树而不只是迭代一个平面列表。我开始认为我的问题可能是我使用了树木行者库,而不是在访问每个节点后用回调编写我自己的算法。
非常感谢你的帮助!
答案 0 :(得分:2)
您的数据库调用是异步的。这意味着他们将在.forEach()
迭代完成很久之后的某个时间完成。如果您的数据库可以处理一次抛出的整个查询树(基本上并行运行所有这些查询),那么您可以做一些简单的事情:
let cntr = 0;
catTree.categoryTree.forEach(function(node){
tree.walkTree(node, 'children', function(obj){
//Cat is a mongoose model defined elsewhere
++cntr;
Cat.findById(obj.categoryId, {_id:0,name:1}).exec(function(err, value){
--cntr;
if (!err) {
obj.name = value.name;
}
// see if all requests are done
if (cntr === 0) {
console.log(JSON.stringify(catTree));
}
});
});
});
每当你试图协调多个异步操作时,通常使用promises是有意义的(因为这正是它们的构建),而mongoose已经为查询内置了promise。在这里,您将每个查询的承诺收集到一个数组中,然后Promise.all()
告诉您它们何时完成。
let promises = [];
catTree.categoryTree.forEach(function(node){
tree.walkTree(node, 'children', function(obj){
//Cat is a mongoose model defined elsewhere
let p = Cat.findById(obj.categoryId, {_id:0,name:1}).exec().then(function(value) {
obj.name = value.name;
});
promises.push(p);
});
});
Promise.all(promises).then(function() {
console.log(JSON.stringify(catTree));
}).catch(function(err) {
// error
console.log(err);
});