嵌套查询的数据在Nodejs中不能共用?
嵌套查询的数据在Nodejs中不能共用?
categoryModel.where({“parent_id”:null}).exec(function(err,docs){ var list=new Array(); var father=[],children=[]; docs.forEach(function(doc,index){ father._id=doc._id; father.name=doc.name; father.childrens=[]; list.push(father); list[index].childrens.push(doc);//我是测试一 categoryModel.where({“parent_id”:doc._id}).exec(function(err,docs2){ docs2.forEach(function(doc2,index2){ children._id=doc2._id; children.name=doc2.name; //list[index].childrens.push(doc2);//我是测试二 }); }); }); console.log(list); });
如上,一个查询中内置了其相关的查询,在上面的2个测试中,测试一的可以加入到数组list的childrens中,而测试二的不能加入到数组list的childrens中,请问这是神马情况,该如何解决呢!!!
嵌套查询的数据在Node.js中不能共用?
在Node.js中处理嵌套查询时,经常遇到数据不能正确共用的情况。这通常是因为异步操作的顺序问题导致的。在你的例子中,内部查询(子查询)没有等待外部查询的结果完成就执行了,导致数据无法正确地填充到父级对象中。
示例代码
假设我们有两个模型 Category
和 SubCategory
,其中 Category
模型包含顶级分类,而 SubCategory
模型包含每个顶级分类下的子分类。
const categoryModel = require('./models/Category');
const subCategoryModel = require('./models/SubCategory');
categoryModel.find({ "parent_id": null }).exec((err, topCategories) => {
if (err) {
console.error(err);
return;
}
const result = topCategories.map(topCategory => ({
_id: topCategory._id,
name: topCategory.name,
children: []
}));
// 并发处理所有顶级分类的子分类查询
Promise.all(topCategories.map(topCategory =>
subCategoryModel.find({ "parent_id": topCategory._id }).exec()
)).then(subCategories => {
// 将子分类添加到对应的顶级分类中
subCategories.forEach((subCategoryList, index) => {
result[index].children = subCategoryList.map(subCategory => ({
_id: subCategory._id,
name: subCategory.name
}));
});
console.log(result);
});
});
解释
- 查询顶级分类:首先从数据库中查询出所有的顶级分类。
- 初始化结果数组:为每个顶级分类创建一个对象,并初始化其
children
属性为空数组。 - 并发处理子分类查询:使用
Promise.all
并发处理每个顶级分类的子分类查询。这样可以确保所有子分类查询都完成后再继续后续操作。 - 填充子分类:将查询到的子分类添加到对应的顶级分类对象中。
- 输出结果:最后输出处理好的结果数组。
通过这种方式,你可以确保所有异步操作按预期顺序执行,并且数据能够正确地填充到对应的父级对象中。
在你的代码中,father
和 children
对象在循环中被多次引用,导致每次修改它们时都会影响之前已经添加到 list
中的对象。为了确保每个对象都是独立的,需要在每次迭代时创建新的对象。
以下是修改后的代码示例:
categoryModel.where({ "parent_id": null }).exec(function (err, docs) {
var list = [];
docs.forEach(function (doc, index) {
// 创建一个新的父亲对象
var father = { _id: doc._id, name: doc.name, childrens: [] };
// 添加当前文档作为子节点
father.childrens.push(doc);
// 再次查询子节点并添加
categoryModel.where({ "parent_id": doc._id }).exec(function (err, docs2) {
docs2.forEach(function (doc2) {
// 创建一个新的子节点对象
var child = { _id: doc2._id, name: doc2.name };
father.childrens.push(child);
});
// 将处理完的父节点添加到列表中
list.push(father);
// 所有查询完成后打印结果
if (index === docs.length - 1) {
console.log(list);
}
});
});
});
解释
- 创建新对象:每次迭代时都创建新的
father
和child
对象,以避免引用问题。 - 异步查询处理:在每个子查询完成后再将处理完的父节点添加到
list
中。 - 最终输出:只有在所有查询都完成之后才打印
list
,以确保数据完整。
这样就能确保每个节点对象是独立的,并且能够正确地嵌套到父节点中。