You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何设计Mongoose商品Schema的分类模块 支持电子、时尚、食品等类目

Mongoose 多类目商品分类模块Schema搭建方案

核心设计思路

采用「公共字段统一存储 + 类目特有字段动态适配」的方案,不需要为每个类目单独建表,同时支持多级分类关联、类目属性合规校验,可灵活扩展任意商品类目。


1. 先搭建分类(Category)模型

用来存储类目层级、每个类目对应的特有属性模板,示例结构如下图:
商品分类层级示意图

对应Mongoose Schema代码:

const mongoose = require('mongoose');
const { Schema } = mongoose;

const categorySchema = new Schema({
  // 分类名称:电子/时尚/食品等一级分类,或手机/笔记本/女装等二级分类
  name: {
    type: String,
    required: true,
    trim: true
  },
  // 父分类ID,一级分类的parentId为null
  parentId: {
    type: Schema.Types.ObjectId,
    ref: 'Category',
    default: null
  },
  // 分类层级:1为一级分类,2为二级分类,以此类推
  level: {
    type: Number,
    required: true,
    min: 1
  },
  // 当前分类的特有属性模板,添加商品时会按照这个模板校验字段
  attributeTemplate: [
    {
      // 属性名:比如内存/尺码/保质期
      attrName: { type: String, required: true },
      // 属性值类型:String/Number/Boolean/Array
      attrType: { type: String, required: true, enum: ['String', 'Number', 'Boolean', 'Array'] },
      // 是否为必填属性
      required: { type: Boolean, default: false },
      // 可选值枚举,比如尺码的可选值为['S','M','L','XL']
      enumValues: { type: Array, default: [] }
    }
  ],
  // 分类状态:是否启用
  isActive: {
    type: Boolean,
    default: true
  }
}, { timestamps: true });

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

2. 搭建商品(Product)主模型

所有类目商品公共字段统一存储,特有属性存入dynamicAttributes字段,关联分类ID实现类目适配:

const productSchema = new Schema({
  // 所有类目通用公共字段
  name: { type: String, required: true, trim: true },
  price: { type: Number, required: true, min: 0 },
  mainImage: { type: String, required: true },
  stock: { type: Number, required: true, min: 0 },
  description: { type: String, default: '' },
  // 关联分类ID,绑定对应类目
  categoryId: {
    type: Schema.Types.ObjectId,
    ref: 'Category',
    required: true
  },
  // 类目特有属性,和关联分类的attributeTemplate对应
  dynamicAttributes: {
    type: Schema.Types.Mixed,
    default: {}
  },
  // 商品上下架状态
  isOnSale: {
    type: Boolean,
    default: true
  }
}, { timestamps: true });

// 预保存中间件:新增/修改商品时,校验动态属性是否符合对应分类的模板要求
productSchema.pre('save', async function(next) {
  const category = await mongoose.model('Category').findById(this.categoryId);
  if (!category) throw new Error('关联分类不存在');
  
  const template = category.attributeTemplate;
  const attrs = this.dynamicAttributes;

  // 校验必填属性是否存在
  template.forEach(attr => {
    if (attr.required && attrs[attr.attrName] === undefined) {
      throw new Error(`缺少必填属性:${attr.attrName}`);
    }
    // 校验属性值类型
    if (attrs[attr.attrName] !== undefined && typeof attrs[attr.attrName] !== attr.attrType.toLowerCase()) {
      throw new Error(`属性${attr.attrName}类型错误,应为${attr.attrType}`);
    }
    // 校验枚举值
    if (attr.enumValues.length > 0 && !attr.enumValues.includes(attrs[attr.attrName])) {
      throw new Error(`属性${attr.attrName}的值不在可选范围内`);
    }
  });
  next();
});

module.exports = mongoose.model('Product', productSchema);

使用示例

新增电子类(手机)商品

// 假设已存在手机分类,属性模板包含「内存、CPU、屏幕尺寸」三个属性
const newPhone = new Product({
  name: 'XX品牌智能手机',
  price: 3999,
  mainImage: 'xxx.jpg',
  stock: 100,
  categoryId: 'xxxxxx(手机分类的ObjectId)',
  dynamicAttributes: {
    内存: '8GB',
    CPU: '骁龙8 Gen2',
    屏幕尺寸: '6.7英寸'
  }
});
await newPhone.save();

新增时尚类(T恤)商品

// 假设已存在T恤分类,属性模板包含「尺码、面料、颜色」三个属性
const newTshirt = new Product({
  name: 'XX品牌纯棉T恤',
  price: 99,
  mainImage: 'xxx.jpg',
  stock: 500,
  categoryId: 'xxxxxx(T恤分类的ObjectId)',
  dynamicAttributes: {
    尺码: 'M',
    面料: '100%棉',
    颜色: '白色'
  }
});
await newTshirt.save();

扩展优化建议

  • 如果需要支持多条件筛选特有属性,可以给dynamicAttributes下的常用字段加索引
  • 可以新增分类参数组的功能,把同类目的通用属性模板批量复用,减少重复配置

内容的提问来源于stack exchange,提问作者Deepak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 16:45:03