如何用Node.js的Sequelize ORM获取10个唯一用户及关联分类
问题根源
你的LIMIT是作用在用户-分类关联后的所有行上,而非唯一用户本身。当一个用户关联多个分类时,会生成多行结果,导致最终返回的唯一用户数量不足10个。
解决方案
1. 直接调整SQL语句
先通过子查询筛选出符合条件的10个唯一用户,再关联分类表获取这些用户的所有分类:
SELECT `User`.*, `userCategories`.`id` AS `userCategories.id`, `userCategories`.`category_id` AS `userCategories.categoryId` FROM ( -- 子查询先拿到10个符合条件的唯一用户ID SELECT `id`, `updatedAt` FROM `users` WHERE `deleted_at` IS NULL AND `country_id` IN (1) AND `is_blocked` = false -- 确保用户关联了指定分类 AND EXISTS ( SELECT 1 FROM `user_categories` WHERE `user_id` = `users`.`id` AND `deleted_at` IS NULL AND `category_id` IN ('129', '203') ) ORDER BY `updatedAt` DESC LIMIT 10 OFFSET 1 ) AS `FilteredUsers` -- 关联主用户表获取完整用户信息 JOIN `users` AS `User` ON `FilteredUsers`.`id` = `User`.`id` -- 关联分类表获取该用户的所有分类 LEFT OUTER JOIN `user_categories` AS `userCategories` ON `User`.`id` = `userCategories`.`user_id` AND `userCategories`.`deleted_at` IS NULL ORDER BY `User`.`updatedAt` DESC;
2. 使用Sequelize ORM实现
方式一:分两步查询(清晰直观)
先筛选出目标用户ID,再查询这些用户及其所有分类:
const { Op, Sequelize } = require('sequelize'); // 假设User和UserCategory是已定义的模型,且关联名为userCategories // 第一步:获取符合条件的10个用户ID const filteredUsers = await User.findAll({ attributes: ['id', 'updatedAt'], where: { deleted_at: null, country_id: [1], is_blocked: false, // 用EXISTS确保用户关联了指定分类 [Op.and]: [ Sequelize.literal(`EXISTS ( SELECT 1 FROM user_categories WHERE user_id = users.id AND deleted_at IS NULL AND category_id IN ('129', '203') )`) ] }, order: [['updatedAt', 'DESC']], limit: 10, offset: 1 }); const userIds = filteredUsers.map(user => user.id); // 第二步:查询这些用户的完整信息及所有分类 const result = await User.findAll({ where: { id: userIds }, include: [{ model: UserCategory, as: 'userCategories', where: { deleted_at: null }, required: false // 保留左连接,即使用户后续没有分类也能返回(可选) }], order: [['updatedAt', 'DESC']] });
方式二:单查询嵌套子查询(更简洁)
直接在WHERE条件中用子查询限定用户ID范围:
const { Op, Sequelize } = require('sequelize'); const result = await User.findAll({ include: [{ model: UserCategory, as: 'userCategories', where: { deleted_at: null }, required: false }], where: { deleted_at: null, country_id: [1], is_blocked: false, id: { [Op.in]: Sequelize.literal(`( SELECT id FROM users WHERE deleted_at IS NULL AND country_id IN (1) AND is_blocked = false AND EXISTS ( SELECT 1 FROM user_categories WHERE user_id = users.id AND deleted_at IS NULL AND category_id IN ('129', '203') ) ORDER BY updatedAt DESC LIMIT 10 OFFSET 1 )`) } }, order: [['updatedAt', 'DESC']] });
注意事项
- 原SQL中WHERE子句存在语法错误:
AND userCategories.category_id IN ('129', '203')前面多了一个多余的AND,需要删除才能正常执行。 - 如果不需要保留没有分类的用户,可以将
required: false改为required: true(内连接),但子查询已经确保用户关联了指定分类,所以两种设置差异不大。
内容的提问来源于stack exchange,提问作者Faizan Ahmed
相关产品推荐
相关产品推荐

