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

如何在Sequelize Postgres中构建Category与Sub-category的一对多关系

在Sequelize中构建Category与SubCategory的一对多关系

要实现一个Category拥有多个SubCategory、一个SubCategory属于一个Category的一对多关系,需要完成两个核心步骤:给SubCategory添加外键字段,以及在两个模型间建立关联绑定。以下是具体的代码修改和实现方案:

1. 修改SubCategory模型,添加外键字段

在SubCategory的模型定义中,新增category_id字段作为关联Category的外键,类型与Category的主键(UUID)保持一致:

const { DataTypes } = require("sequelize");
const { getConnection } = require("../helper/databaseConnection");

const subcatModel = {
  subcat_id: {
    primaryKey: true,
    type: DataTypes.UUID,
    defaultValue: DataTypes.UUIDV4,
  },
  subcat_name: {
    type: DataTypes.STRING,
    allowNull: false,
  },
  // 新增外键字段,关联Category的category_id
  category_id: {
    type: DataTypes.UUID,
    allowNull: false,
    references: {
      model: 'category', // 对应Category模型的表名(因freezeTableName: true,表名即为category)
      key: 'category_id'
    },
    onDelete: 'CASCADE', // 可选:删除分类时自动删除其子分类,也可设为RESTRICT禁止删除有子分类的分类
    onUpdate: 'CASCADE'
  }
};

let subcat = null;
const initSubcatModel = async () => {
  try {
    if (subcat) return subcat;
    const sequelize = await getConnection();
    subcat = sequelize.define("sub_category", subcatModel, {
      freezeTableName: true,
    });

    await subcat.sync({ alter: true });
    return subcat;
  } catch (err) {
    console.log("sub category", err);
  }
};

module.exports = { initSubcatModel };

2. 统一初始化模型并建立关联

由于两个模型都是异步初始化的,需要确保两者都初始化完成后再调用关联方法。建议创建一个统一的初始化文件(比如models/index.js)来处理:

const { initCategoryModel } = require('./category');
const { initSubcatModel } = require('./sub-category');

async function initModels() {
  const Category = await initCategoryModel();
  const SubCategory = await initSubcatModel();

  // 建立一对多关联
  Category.hasMany(SubCategory, {
    foreignKey: 'category_id', // 对应SubCategory中的外键字段
    as: 'subcategories' // 查询时的别名,用于包含子分类数据
  });

  SubCategory.belongsTo(Category, {
    foreignKey: 'category_id',
    as: 'category' // 查询时的别名,用于包含父分类数据
  });

  return { Category, SubCategory };
}

module.exports = { initModels };

3. 关联后的使用示例

完成关联后,就可以通过include选项查询关联数据:

const { initModels } = require('./models');

// 查询指定分类及其所有子分类
async function getCategoryWithSubcats(categoryId) {
  const { Category } = await initModels();
  const category = await Category.findByPk(categoryId, {
    include: ['subcategories'] // 使用关联时定义的别名
  });
  return category;
}

// 查询指定子分类及其所属分类
async function getSubcatWithCategory(subcatId) {
  const { SubCategory } = await initModels();
  const subcat = await SubCategory.findByPk(subcatId, {
    include: ['category']
  });
  return subcat;
}

注意事项

  • references.model必须与Category模型的表名一致(因设置了freezeTableName: true,表名就是category)
  • onDelete和onUpdate可根据业务需求调整:若不希望删除分类时删除子分类,可设为RESTRICT;若允许子分类不属于任何分类,可将allowNull设为true并将onDelete设为SET NULL
  • 必须在两个模型都初始化完成后再调用关联方法,否则会出现模型未定义的错误

内容的提问来源于stack exchange,提问作者sumanth.js

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 06:35:17