Nodejs + mongoose 如何写递归?

Nodejs + mongoose 如何写递归?

如题,由于异步,请如使用mongoose, 如何获取树结果?

4 回复

当然可以。在 Node.js 中使用 Mongoose 操作数据库时,处理递归查询是一个常见的需求,特别是在处理具有嵌套关系的数据结构(例如树形结构)时。以下是如何实现递归查询以获取树形结构数据的示例。

示例场景

假设我们有一个 Category 模型,每个类别可以有子类别,我们需要递归地获取某个类别的所有子类别。

定义模型

首先,定义一个 Category 模型:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const CategorySchema = new Schema({
    name: { type: String, required: true },
    children: [{ type: Schema.Types.ObjectId, ref: 'Category' }]
});

module.exports = mongoose.model('Category', CategorySchema);

递归函数

接下来,编写一个递归函数来获取某个类别的所有子类别:

const Category = require('./models/Category'); // 引入模型

async function getChildrenTree(categoryId) {
    const category = await Category.findById(categoryId).populate('children');

    if (!category) {
        return null;
    }

    const childrenPromises = category.children.map(async (child) => {
        return {
            ...child.toObject(),
            children: await getChildrenTree(child._id)
        };
    });

    const children = await Promise.all(childrenPromises);

    return {
        ...category.toObject(),
        children: children.filter(Boolean) // 过滤掉没有子类别的空对象
    };
}

// 使用示例
getChildrenTree('5f9c8e4b2d3f4a57d8b0f123')
    .then(tree => console.log(JSON.stringify(tree, null, 2)))
    .catch(err => console.error(err));

解释

  1. 模型定义

    • Category 模型有一个 children 字段,它是一个引用到其他 Category 对象的数组。
  2. 递归函数

    • getChildrenTree 函数接受一个类别ID,并查找该类别及其所有子类别。
    • 使用 populate 方法将 children 字段填充为实际的类别对象。
    • 使用 mapPromise.all 处理每个子类别,递归调用 getChildrenTree 函数。
    • 最终返回包含所有子类别的树形结构。

通过这种方式,你可以递归地获取并构建出完整的树形结构数据。


一次性全部拿出来

但是查询子树,需要父类的ID,求帮助.

在Node.js中使用Mongoose处理递归查询时,通常会遇到异步操作的问题。为了实现递归查询(例如,获取嵌套分类或评论树结构),我们可以使用异步函数和async/await来简化代码并保持逻辑清晰。

假设我们有一个模型Category,其中每个类别可以包含子类别。我们需要编写一个函数来递归地获取所有子类别的数据。

示例代码

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// 定义Category模型
const CategorySchema = new Schema({
    name: String,
    children: [{ type: Schema.Types.ObjectId, ref: 'Category' }]
});

const Category = mongoose.model('Category', CategorySchema);

// 递归函数用于获取所有子类别的数据
async function getChildrenTree(categoryId) {
    const category = await Category.findById(categoryId).populate('children');

    if (!category.children.length) {
        return [category];
    }

    const childTrees = await Promise.all(
        category.children.map(async (childId) => {
            const childTree = await getChildrenTree(childId);
            return childTree;
        })
    );

    // 展平数组
    const flattenedChildTrees = childTrees.flat();

    return [category, ...flattenedChildTrees];
}

// 使用示例
async function main() {
    const initialCategoryId = 'some-category-id';
    const tree = await getChildrenTree(initialCategoryId);
    console.log(tree);
}

main();

解释

  1. 定义模型:首先定义了一个Category模型,其中包含一个引用自身模型的children字段。
  2. 递归函数getChildrenTree函数通过传入一个categoryId参数开始递归。它首先查找给定ID的分类,并使用populate方法填充children字段。
  3. 递归调用:如果当前分类没有子分类,则返回该分类。否则,对每个子分类进行递归调用,并将结果组合成一个完整的树结构。
  4. 扁平化数组:使用flat()方法将嵌套的数组展平,以确保最终返回的树结构是正确的。
  5. 使用示例main函数展示了如何使用上述递归函数获取树结构。

这种方式利用了async/await来处理异步操作,使得代码更加易读和易于维护。

回到顶部