在自定义字段上使用两个 JOIN 对查询进行 Sequelize
Sequelize query with two JOINs on custom fields
目前我有一个使用以下原始查询的解决方案,效果很好。
这是一个SqlFiddle playground。
下面是运行良好的原始查询:
const sql = `SELECT u.*, g.name AS "gender"
FROM users u
INNER JOIN connections con ON con.user_id = u.id
INNER JOIN completed_quizzes q ON q.user_id = u.id
LEFT JOIN genders g ON g.id = u.gender_id
WHERE
con.other_user_id='foo'
AND q.quiz_id=1
AND con.status='approved'
AND u.deleted_at IS NULL
AND con.deleted_at IS NULL
AND q.deleted_at IS NULL
LIMIT 10
OFFSET 0
`;
但我正在尝试用 Sequelize 的对象建模来替换它。到目前为止,我想出的最有意义的解决方案是:
const sequelize = {
include: [
{
model: ConnectionsModel,
as: 'connections',
where: { otherUserId: userId, status: ConnectionStatus.approved },
required: true,
duplicating: false
},
{
model: CompletedQuizzesModel,
as: 'completedQuizzes',
where: { userId, quizId },
required: true,
duplicating: false
},
{
model: GendersModel
}
],
nest: true,
// have to specify `raw: false`, otherwise Sequelize returns only the first associated record
raw: false
};
它生成以下查询(为了便于阅读,我对其进行了美化):
SELECT u.*, g.name AS gender FROM users AS u
INNER JOIN connections AS con ON u.id = con.user_id AND (con.status = 'approved' AND con.other_user_id = 'foo')
INNER JOIN completed_quizzes AS q ON u.id = q.user_id AND (q.user_id = 'foo' AND q.quiz_id = '1')
LEFT OUTER JOIN genders AS g ON u.gender_id = g.id
WHERE u.deleted_at IS NULL
LIMIT 20
OFFSET 0;
但它 returns 什么都没有...没有行。而原始解决方案 returns 根据需要添加行。
我可以看到一般 where
(应用于原始查询中的整个查询)和附加到 [=15= 中的 on
子句的相同属性之间的区别]s。不过不确定这是否是问题所在。
您在 include
选项 CompletedQuizzesModel
中添加了一个额外条件。在原始 SQL 查询中,您没有条件 userId
.
所以这个include
应该是这样的:
{
model: CompletedQuizzesModel,
as: 'completedQuizzes',
where: { quizId }, // removed userId
required: true,
duplicating: false
}
结果查询与原始查询一样:
SELECT u.*, g.name AS gender FROM users AS u
INNER JOIN connections AS con ON u.id = con.user_id AND (con.status = 'approved' AND con.other_user_id = 'foo')
INNER JOIN completed_quizzes AS q ON u.id = q.user_id AND (q.quiz_id = '1')
LEFT OUTER JOIN genders AS g ON u.gender_id = g.id
WHERE u.deleted_at IS NULL
LIMIT 20
OFFSET 0;
目前我有一个使用以下原始查询的解决方案,效果很好。
这是一个SqlFiddle playground。
下面是运行良好的原始查询:
const sql = `SELECT u.*, g.name AS "gender"
FROM users u
INNER JOIN connections con ON con.user_id = u.id
INNER JOIN completed_quizzes q ON q.user_id = u.id
LEFT JOIN genders g ON g.id = u.gender_id
WHERE
con.other_user_id='foo'
AND q.quiz_id=1
AND con.status='approved'
AND u.deleted_at IS NULL
AND con.deleted_at IS NULL
AND q.deleted_at IS NULL
LIMIT 10
OFFSET 0
`;
但我正在尝试用 Sequelize 的对象建模来替换它。到目前为止,我想出的最有意义的解决方案是:
const sequelize = {
include: [
{
model: ConnectionsModel,
as: 'connections',
where: { otherUserId: userId, status: ConnectionStatus.approved },
required: true,
duplicating: false
},
{
model: CompletedQuizzesModel,
as: 'completedQuizzes',
where: { userId, quizId },
required: true,
duplicating: false
},
{
model: GendersModel
}
],
nest: true,
// have to specify `raw: false`, otherwise Sequelize returns only the first associated record
raw: false
};
它生成以下查询(为了便于阅读,我对其进行了美化):
SELECT u.*, g.name AS gender FROM users AS u
INNER JOIN connections AS con ON u.id = con.user_id AND (con.status = 'approved' AND con.other_user_id = 'foo')
INNER JOIN completed_quizzes AS q ON u.id = q.user_id AND (q.user_id = 'foo' AND q.quiz_id = '1')
LEFT OUTER JOIN genders AS g ON u.gender_id = g.id
WHERE u.deleted_at IS NULL
LIMIT 20
OFFSET 0;
但它 returns 什么都没有...没有行。而原始解决方案 returns 根据需要添加行。
我可以看到一般 where
(应用于原始查询中的整个查询)和附加到 [=15= 中的 on
子句的相同属性之间的区别]s。不过不确定这是否是问题所在。
您在 include
选项 CompletedQuizzesModel
中添加了一个额外条件。在原始 SQL 查询中,您没有条件 userId
.
所以这个include
应该是这样的:
{
model: CompletedQuizzesModel,
as: 'completedQuizzes',
where: { quizId }, // removed userId
required: true,
duplicating: false
}
结果查询与原始查询一样:
SELECT u.*, g.name AS gender FROM users AS u
INNER JOIN connections AS con ON u.id = con.user_id AND (con.status = 'approved' AND con.other_user_id = 'foo')
INNER JOIN completed_quizzes AS q ON u.id = q.user_id AND (q.quiz_id = '1')
LEFT OUTER JOIN genders AS g ON u.gender_id = g.id
WHERE u.deleted_at IS NULL
LIMIT 20
OFFSET 0;