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

如何使用Sequelize生成关联表查询?含用户-角色场景

搞定Sequelize用户-角色关联查询及角色搜索需求

嘿,我来帮你解决这个问题,结合你的需求和现有模型,咱们先把模型里的小问题修正,再一步步实现你要的功能:

首先,你的userRole模型里有个明显的错误——userId字段被误设成了主键还开了自增,这肯定会出问题(毕竟表已经有id作为主键了),而且原模型里你把role字段写成了password,这显然不是你要的,正确的模型定义应该是这样:

const userRole = sequelize.define('userRole', {
    id: {
        type: DataTypes.BIGINT,
        allowNull: false,
        primaryKey: true,
        autoIncrement: true,
        field: 'id'
    },
    userId: {
        type: DataTypes.BIGINT,
        allowNull: false,
        field: 'user_id'
    },
    role: { // 这里应该是role字段,对应你的SQL里的role属性
        type: DataTypes.STRING(200),
        allowNull: false,
        field: 'role'
    }
}, { tableName: 'user_role' }); // 数据库表名和你的SQL里的user_role保持一致,下划线命名更规范

关联定义可以调整成和模型字段对应(其实之前的也能用,但调整后逻辑更清晰):

user.hasMany(models.userRole, { foreignKey: 'userId', as: 'roles' });
userRole.belongsTo(models.user, { foreignKey: 'userId', as: 'user' });

接下来实现你要的核心需求:当用户的任一角色匹配搜索条件时,返回该用户及其所有关联角色:

方式一:贴近你给出的SQL语句实现

如果要严格对应你写的SQL结构,我们可以用Sequelize的literal()结合子查询来实现,同时加入搜索条件:

const { Op } = require('sequelize');
const searchRole = 'admin'; // 假设这是前端传入的搜索关键词

const users = await user.findAll({
    include: [
        {
            model: userRole,
            as: 'roles',
            attributes: [],
            required: true, // 对应INNER JOIN,确保只返回有匹配角色的用户
            where: sequelize.literal(`EXISTS (
                SELECT 1 FROM user_role ur 
                WHERE ur.user_id = user.id 
                AND ur.role LIKE '%${searchRole}%'
            )`)
        }
    ],
    attributes: {
        include: [
            // 用子查询获取当前用户的所有角色,聚合为数组
            [sequelize.literal(`(
                SELECT JSON_ARRAYAGG(ur.role) 
                FROM user_role ur 
                WHERE ur.user_id = user.id
            )`), 'rolesList']
        ]
    },
    group: ['user.id'], // 按用户ID分组,避免重复返回同一用户
    order: [[sequelize.literal('rolesList'), 'ASC']] // 按角色排序
});

方式二:更符合Sequelize风格的实现(推荐)

如果不需要严格照搬SQL结构,优先考虑业务逻辑清晰和可维护性,我们可以分两步走:先筛选出有匹配角色的用户ID,再查询这些用户的完整信息及所有角色。这种方式更适合前端表格展示的需求:

const { Op } = require('sequelize');
const searchRole = 'admin';

// 第一步:找出所有拥有匹配角色的用户ID
const matchedUserIds = await userRole.findAll({
    attributes: ['userId'],
    where: {
        role: {
            [Op.like]: `%${searchRole}%`
        }
    },
    group: ['userId'] // 去重,避免同一个用户ID多次返回
}).then(rows => rows.map(row => row.userId));

// 第二步:查询这些用户的所有信息及关联的所有角色
const users = await user.findAll({
    include: [
        {
            model: userRole,
            as: 'roles',
            required: false // 用LEFT JOIN确保即使角色有变动也能返回,但我们已经筛选了有匹配角色的用户
        }
    ],
    where: {
        id: {
            [Op.in]: matchedUserIds
        }
    }
});

这样返回的结果里,每个用户都会带上自己所有的角色,同时只有角色匹配搜索条件的用户才会被返回,完全符合你的API需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 08:27:50