I'm running an into issue where Sequelize creates a subquery of the primary model and then joins the includes with that subquery instead of directly with the primary model table. The query conditions for the include(s) ends up inside the subquery's WHERE clause which makes it invalid. I have shortened names down trying to keep this compact hopefully without losing any relevant info.
Environment: Nodejs: 6.11.3 Sequelize: 3.23.6 => Updated to 4.38.1 and problem persists MySql: 5.7.23
Code snip models:
I.model:
models.I.hasMany(models.II);
models.I.belongsTo(models.CJ);
models.I.belongsTo(models.CJS);
II.model:
models.II.belongsTo(models.I);
CJ.model:
models.CJ.hasMany(models.I);
models.CJ.hasMany(models.CJS);
CJS.model:
models.CJS.hasMany(models.I);
Code snip query definition:
let where = { cId: '2',
iAmt: { '$gt': 0 },
'$or':
[ { '$CJ.a1$': {$like: '%246%'}} },
{ '$CJ.a2$': {$like: '%246%'} },
{ '$I.cPN$': {$like: '%246%'} }
] };
let query = {
where: where,
order: orderBy,
distinct: true,
offset: offset,
limit: limit,
include: [
{
model: CJ,
as: 'CJ',
required: false
}, {
model: CJS,
as: 'CJS',
required: false
}, {
model: II,
as: 'IIs',
required: false
}
]
};
I.findAll(query)
Produces SQL like the following:
SELECT `I`.*, `CJ`.`_id` AS `CJ._id`, `CJS`.`_id` AS `CJS._id`, `IIs`.`_id` AS `IIs._id`
FROM (SELECT `I`.`_id`, `I`.`CJId`, `I`.`CJSId`, `I`.`CId`
FROM `Is` AS `I`
WHERE `I`.`CId` = '2' AND
`I`.`iA` > 0 AND
(`CJ`.`a1` LIKE '%246%' OR
`CJ`.`a2` LIKE '%246%' OR
`I`.`cPN` LIKE '%246%'
)
ORDER BY `I`.`iNum` DESC LIMIT 0, 10) AS `I`
LEFT OUTER JOIN `CJs` AS `CJ` ON `I`.`CJId` = `CJ`.`_id`
LEFT OUTER JOIN `CJSs` AS `CJS` ON `I`.`CJSId` = `CJS`.`_id`
LEFT OUTER JOIN `IIs` AS `IIs` ON `I`.`_id` = `IIs`.`IId`
ORDER BY `I`.`iNum` DESC;
I was expecting something like this:
SELECT `I`.*, `CJ`.`_id` AS `CJ._id`, `CJS`.`_id` AS `CJS._id`, `IIs`.`_id` AS `IIs._id`
FROM `Is` AS `I`
LEFT OUTER JOIN `CJs` AS `CJ` ON `I`.`CJId` = `CJ`.`_id`
LEFT OUTER JOIN `CJSs` AS `CJS` ON `I`.`CJSId` = `CJS`.`_id`
LEFT OUTER JOIN `IIs` AS `IIs` ON `I`.`_id` = `IIs`.`IId`
WHERE `I`.`CId` = '2' AND
`I`.`iA` > 0 AND
(`CJ`.`a1` LIKE '%246%' OR
`CJ`.`a2` LIKE '%246%' OR
`I`.`cPN` LIKE '%246%'
)
ORDER BY `I`.`iNum` DESC LIMIT 0, 10
If I remove the II model from the include it does work and moves the the WHERE to the top level. I admit the structure of the query is not straight forward here, with I being a child of CJ and CJS, which in turn is a child of CJ. And then II a child of I. What am I missing here?
Bueller's or anyone's 2 cent welcome!
what happened here is because you also using order
and limit
together with eager loading association see the issue
to make it work, there is a little hacky solution, you need to add subQuery: false
together to your root model query
let query = {
where: where,
order: orderBy,
distinct: true,
offset: offset,
limit: limit,
subQuery: false,
include: [...]
};
来源:https://stackoverflow.com/questions/52303647/sequelize-top-level-where-with-eagerly-loaded-models-creates-sub-query