如何在Node.js中处理无限层级子分类数组并插入数据库
问题
需要将包含无限层级子分类的Payload数据插入数据库,每个分类对象包含name字段和child_categories子数组,要求每条分类记录携带其父分类的parent_category_id。当前代码仅能处理固定层级的分类插入,无法适配无限层级场景,如何循环处理这类数组完成数据库插入?
Payload结构
{ "name": "food", "child_categories": [ { "name": "non-frozen", "child_categories": [ { "name":"non-branded", "child_categories": [ { "name":"food-grains", "child_categories": [ { "name":"rice" }, { "name": "atta" }, { "name": "maida" }, { "name": "sooji" }, { "name":"ragi" }, { "name": "jower" }, { "name": "bajra" } ] }, { "name":"salt&spices", "child_categories": [ { "name":"whole-spices" }, { "name":"grounded-spices" } ] }, { "name":"dried-condiments", "child_categories": [ { "name":"salt" }, { "name":"powders" }, { "name":"sugar" }, { "name":"jaggery" } ] }, { "name": "edible-oil&ghee" }, { "name": "lentils", "child_categories":[ { "name":"all-dals" }, { "name":"all-rajma" }, { "name":"chanas" }, { "name":"millets" }, { "name":"soya" } ] } ] }, { "name":"branded", "child_categories": [ { "name":"food-grains", "child_categories": [ { "name":"rice" }, { "name": "atta" }, { "name": "maida" }, { "name": "sooji" }, { "name":"ragi" }, { "name": "jower" }, { "name": "bajra" } ] }, { "name":"salt&spices", "child_categories": [ { "name":"whole-spices" }, { "name":"grounded-spices" } ] }, { "name":"dried-condiments", "child_categories": [ { "name":"salt" }, { "name":"powders" }, { "name":"sugar" }, { "name":"jaggery" } ] }, { "name": "edible-oil&ghee" }, { "name": "lentils", "child_categories":[ { "name":"all-dals" }, { "name":"all-rajma" }, { "name":"chanas" }, { "name":"millets" }, { "name":"soya" } ] }, { "name":"snacks&cereals", "child_categories":[ { "name":"biscuits" }, { "name":"cookies" }, { "name":"bhujia" }, { "name":"mixture" } ] }, { "name":"packaged-raw", "child_categories":[ { "name":"noodles" }, { "name":"pasta" }, { "name":"macaroni" }, { "name":"spreads" }, { "name":"sauces" }, { "name":"ready-to-eat" }, { "name":"chocs" }, { "name":"pickles&chutney" } ] } ] } ] } ] }
数据库存储示例
{ "_id": "1", "parent_category_id": null, // 一级分类 "name":"food" } { "_id":2, "parent_category_id": 1, "name": "non-frozen" } { "_id": 3, "parent_category_id": 2, "name": "non-branded" } { "_id": 4, "parent_category_id": 3, "name": "food-grains" } // 以此类推...
现有代码(仅支持固定层级)
let payload = req.payload let obj1 = { "name": payload.name, "parent_category_id": null, "created_by": userId, "updated_by": userId } let parent_category = await Category.create(obj1) if (!!payload.childCategories){ payload.childCategories.forEach(async item => { if(!!item){ let obj2 = { "name": item.name, "parent_category_id": parent_category._id, "created_by": userId, "updated_by": userId } let parent_category1 = await Category.create(obj2) if (!!item.childCategories){ payload.childCategories.forEach(async item1 => { let obj3 = { "name": item1.name, "parent_category_id": parent_category1._id, "created_by": userId, "updated_by": userId } let parent_category2 = await Category.create(obj3) }) } } }) }
解决方案
核心思路是用递归函数处理无限层级的嵌套分类,递归函数负责插入当前分类,并自动递归处理其所有子分类。同时修复原代码中异步流程失控、硬编码层级的问题。
修正后的代码
// 递归插入分类的核心函数 async function insertCategories(category, parentId, userId) { // 插入当前分类 const categoryDoc = await Category.create({ name: category.name, parent_category_id: parentId, created_by: userId, updated_by: userId }); // 处理当前分类的子分类 if (category.child_categories && category.child_categories.length > 0) { // 使用for...of替代forEach,确保异步流程顺序执行 for (const child of category.child_categories) { await insertCategories(child, categoryDoc._id, userId); } } } // 调用入口 async function handleCategoryInsert(req) { const payload = req.payload; const userId = req.user._id; // 根据实际业务获取用户ID await insertCategories(payload, null, userId); return { message: "所有分类插入完成" }; }
代码说明
递归函数逻辑:
- 每次调用先插入当前分类,获取生成的
_id - 若当前分类存在子分类,就遍历每个子分类,递归调用自身,将当前分类的
_id作为子分类的parent_category_id - 无论嵌套多少层,都会逐层处理直到所有分类插入完成
- 每次调用先插入当前分类,获取生成的
异步流程修复:
- 用
for...of替代forEach,forEach无法配合async/await保证顺序,for...of可以确保每个子分类插入完成后再处理下一个,避免数据库插入顺序混乱
- 用
原代码问题修复:
- 去掉硬编码的层级逻辑,适配任意嵌套深度
- 修正了第二层遍历错误的数组(原代码错误遍历根分类的子数组,而非当前分类的子数组)
- 统一异步流程控制,避免并行插入导致的异常
内容的提问来源于stack exchange,提问作者Rekha
相关产品推荐
相关产品推荐

