如何用sequelize提供的方法,实现多对多联表查询?

我们以 RBAC(Role-Based Access Control,基于角色的访问控制)来举例说明。
简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。(如下图)

在这里插入图片描述

这里我们先以用户表和角色表的关联查询为例子,我们引入了一个用户角色关联表,来绑定用户id和角色id之间的对应关系。

模型的定义

数据库中的表之间存在一定的关联关系,表之间的关系基于主/外键进行关联、创建约束等。关系表中的数据分为1对1(1:1)、1对多(1:M)、多对多(N:M)三种关联关系。

在Sequelize中建立关联关系,通过调用模型(源模型)的belongsTo、hasOne、hasMany、belongsToMany方法,再将要建立关系的模型(目标模型)做为参数传入即可。

model建好后,需要在model导出前,通过model.associate方法来指定表和表之间的关联关系。而在有中间表的情况下,可以直接在中间表里指定了关系,另外两张表就不需要去重复指定了。具体代码如下:

用户表模型:app.model.Users
'use strict';
const moment = require('moment');

module.exports = app => {
  const { STRING, INTEGER, DATE} = app.Sequelize;

  const User = app.model.define('users', {
    id: { type: INTEGER, primaryKey: true, autoIncrement: true }, // 主键,自增
    username: { type: STRING(30), allowNull: false, unique: true }, // 不允许为空,必须唯一
    mobile: { type: STRING}, // 手机号
    created_at: {	
      type: DATE,
      get() {
      	//获取时间时格式化
        return moment(this.getDataValue('created_at')).format('YYYY-MM-DD HH:mm:ss');
      },
    },
    updated_at: {
      type: DATE,
      get() {
        return moment(this.getDataValue('created_at')).format('YYYY-MM-DD HH:mm:ss');
      },
    },
  }, {
    freezeTableName: true, // 防止修改表名为复数
  });

  return User;
};

角色表模型:app.model.Role
'use strict';

module.exports = app => {
  const { STRING, INTEGER } = app.Sequelize;

  const Role = app.model.define('role', {
    id: { type: INTEGER, primaryKey: true, autoIncrement: true }, // 主键,自增
    name: { type: STRING(30), unique: true },
    describe: STRING(60),
  }, {
    freezeTableName: true,
  });

  return Role;
};

用户角色关联表模型:app.model.UsersRole
'use strict';

module.exports = app => {
  const { INTEGER, DATE } = app.Sequelize;

  const UsersRole = app.model.define('users_role', {
    id: { type: INTEGER, primaryKey: true, autoIncrement: true }, // 主键,自增
    users_id: { type: INTEGER },
    role_id: { type: INTEGER },
    created_at: DATE,
    updated_at: DATE,
  }, {
    freezeTableName: true, 
  });

  UsersRole.associate = function() {
    // 用belongsToMany指定多对多关联关系,并指定外键
    app.model.User.belongsToMany(app.model.Role, {
      through: UsersRole,
      foreignKey: 'users_id',
      otherKey: 'role_id',
    });
    app.model.Role.belongsToMany(app.model.User, {
      through: UsersRole,
      foreignKey: 'role_id',
      otherKey: 'users_id',
    });
  };

  return UsersRole;
};

在controller.Users里实现联表查询

在findAll方法里,通过include参数引入需要关联的表,这时候这两个表的外键早已在创建用户角色模型时指定好了,直接引入角色模型就可以实现联表查询。

async getUserList() {
    const { ctx } = this;
    const id = toInt(ctx.request.body.userId);
    const users = await ctx.model.User.findAll({
      include: [
        { model: ctx.model.Role },
      ],
      where: {
        id,
      },
    });
    if (!user) {
      ctx.status = 404;
      return;
    }
    ctx.body = {result:users}
}

查询出来的结果,会在users列表里的每个user里,会多出一个roles的角色列表

"result": [
		{
			"created_at": "2022-02-23 13:27:50",
			"updated_at": "2022-02-23 13:27:50",
			"id": 999,
			"username": "Tony",
			"roles": [
				{
					"id": 1,
					"name": "超级管理",
					"describe": "eee23456",
					"createdAt": "2022-02-23T02:59:21.000Z",
					"updatedAt": "2022-02-24T06:41:33.000Z",
					"users_role": {
						"id": 1,
						"users_id": 999,
						"role_id": 1,
						"createdAt": "2022-02-24T08:13:38.000Z",
						"updatedAt": "2022-02-24T08:13:42.000Z"
					}
				}
			]
		}
	]

这里我们只讨论了复杂点的多对多情况,其他联表方法可以参考官网文档:【点击跳转到sequlize文档】

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐