Amin Azimi
Amin Azimi

Reputation: 749

Mongodb unlimited nested category, sub-category and sub-sub-category and so on

I created an e-commerce website but want to change a couple of features of it, I want to allow users to create unlimited categories and subcategories. what is the best approach for it? I used Nodejs (express) and MongoDB (mongoose). Currently, the DB schema is this one:

category.js

const mongoose = require('mongoose');
const { s, rs, n, ref } = require('../utils/mongo');

var schema = new mongoose.Schema(
  {
    user: ref('user'),
    name: { ...rs, unique: true },
    description: s,
    image: s,
    view: {
      ...n,
      default: 0,
    },
  },
  { timestamps: true }
);

module.exports = mongoose.model('category', schema);

subcategory.js

const mongoose = require('mongoose');
const { s, rs, ref } = require('../utils/mongo');

var schema = new mongoose.Schema(
  {
    category: ref('category'),
    name: { ...rs, unique: true },
    description: s,
  },
  { timestamps: true }
);

module.exports = mongoose.model('subcategory', schema);

Appreciate in advance

Upvotes: 0

Views: 2342

Answers (2)

Ismail Hosen
Ismail Hosen

Reputation: 206

just use one model

import mongoose from "mongoose";

const CategorySchema = new mongoose.Schema({
    name: {
        type: String,
        required: true,
        unique: true
    },
    slug: {
        type: String,
        required: true,
        unique: true
    },
    parent_id: {
        type: mongoose.Schema.Types.ObjectId,
        default: null
    },
    description: {
        type: String,
        default: null
    },
    image: {
        url: String,
        public_id: String
    },
});

export mongoose.model('Category', CategorySchema);

// Create category
import { Category } from "./model/category.model"
const createCategory = async (data) => {
    try {
        return await new Category(data).save()
    } catch (err) {
        console.log(err)
    }
}

// Get all category
const getAllCategory = async () => {
    try {
        const categories = await Category.find({});
        if (!categories) return [];
        return nestedCategories(categories);
    } catch (err) {
        console.log(err);
    }
}

function nestedCategories(categories, parentId = null) {
    const categoryList = [];
    let category;
    if (parentId == null) {
        category = categories.filter(cat => cat.parent_id == null);
    } else {
        category = categories.filter(cat => String(cat.parent_id) == String(parentId));
    }

    for (let cate of category) {
        categoryList.push({
            _id: cate._id,
            name: cate.name,
            slug: cate.slug,
            children: nestedCategories(categories, cate._id)
        })
    }
    return categoryList;
}

Upvotes: 3

Someone Special
Someone Special

Reputation: 13588

If you want unlimited nested category you will only need one single category schema.

let schema = new mongoose.Schema(
  {
    user: ref('user'),
    name: { ...rs, unique: true },
    description: s,
    image: s,
    parent: { type: mongoose.Schema.Types.ObjectId }, //the parent category
    view: {
      ...n,
      default: 0,
    },
  },
  { timestamps: true }
);

module.exports = mongoose.model('category', schema);

Unfortunately, you cannot use populate and $lookup without specifying a specific level, so you need build the tree yourself if you need unlimited nested.

Upvotes: 0

Related Questions