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));
解释
-
模型定义:
Category模型有一个children字段,它是一个引用到其他Category对象的数组。
-
递归函数:
getChildrenTree函数接受一个类别ID,并查找该类别及其所有子类别。- 使用
populate方法将children字段填充为实际的类别对象。 - 使用
map和Promise.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();
解释
- 定义模型:首先定义了一个
Category模型,其中包含一个引用自身模型的children字段。 - 递归函数:
getChildrenTree函数通过传入一个categoryId参数开始递归。它首先查找给定ID的分类,并使用populate方法填充children字段。 - 递归调用:如果当前分类没有子分类,则返回该分类。否则,对每个子分类进行递归调用,并将结果组合成一个完整的树结构。
- 扁平化数组:使用
flat()方法将嵌套的数组展平,以确保最终返回的树结构是正确的。 - 使用示例:
main函数展示了如何使用上述递归函数获取树结构。
这种方式利用了async/await来处理异步操作,使得代码更加易读和易于维护。

