嵌套查询的数据在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中,请问这是神马情况,该如何解决呢!!!


2 回复

嵌套查询的数据在Node.js中不能共用?

在Node.js中处理嵌套查询时,经常遇到数据不能正确共用的情况。这通常是因为异步操作的顺序问题导致的。在你的例子中,内部查询(子查询)没有等待外部查询的结果完成就执行了,导致数据无法正确地填充到父级对象中。

示例代码

假设我们有两个模型 CategorySubCategory,其中 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);
    });
});

解释

  1. 查询顶级分类:首先从数据库中查询出所有的顶级分类。
  2. 初始化结果数组:为每个顶级分类创建一个对象,并初始化其 children 属性为空数组。
  3. 并发处理子分类查询:使用 Promise.all 并发处理每个顶级分类的子分类查询。这样可以确保所有子分类查询都完成后再继续后续操作。
  4. 填充子分类:将查询到的子分类添加到对应的顶级分类对象中。
  5. 输出结果:最后输出处理好的结果数组。

通过这种方式,你可以确保所有异步操作按预期顺序执行,并且数据能够正确地填充到对应的父级对象中。


在你的代码中,fatherchildren 对象在循环中被多次引用,导致每次修改它们时都会影响之前已经添加到 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);
            }
        });
    });
});

解释

  • 创建新对象:每次迭代时都创建新的 fatherchild 对象,以避免引用问题。
  • 异步查询处理:在每个子查询完成后再将处理完的父节点添加到 list 中。
  • 最终输出:只有在所有查询都完成之后才打印 list,以确保数据完整。

这样就能确保每个节点对象是独立的,并且能够正确地嵌套到父节点中。

回到顶部