我有以下型号:
const User = Sequelize.define('user', {
login: Sequelize.DataTypes.STRING,
password: Sequelize.DataTypes.STRING,
is_manager: Sequelize.DataTypes.BOOLEAN,
notes: Sequelize.DataTypes.STRING
});
const Bike = Sequelize.define('bike', {
model: Sequelize.DataTypes.STRING,
photo: Sequelize.DataTypes.BLOB,
color: Sequelize.DataTypes.STRING,
weight: Sequelize.DataTypes.FLOAT,
location: Sequelize.DataTypes.STRING,
is_available: Sequelize.DataTypes.BOOLEAN
});
const Rate = Sequelize.define('rate', {
rate: Sequelize.DataTypes.INTEGER
});
Rate.belongsTo(User);
User.hasMany(Rate);
Rate.belongsTo(Bike);
Bike.hasMany(Rate);
我想选择平均费用加上每辆自行车的当前用户费用的自行车:
Bike.findAll({
attributes: {include: [[Sequelize.fn('AVG', Sequelize.col('rates.rate')), 'rate_avg']],
},
include: [{
model: Rate,
attributes: []
}, {
model: Rate,
attributes: ['rate'],
include: [{
model: User,
attributes: [],
where: {
login: req.user.login
}
}]
}],
group: Object.keys(Bike.rawAttributes).map(key => 'bike.' + key) // group by all fields of Bike model
})
它构造以下查询:SELECT [bike].[id], [bike].[model], [bike].[photo], [bike].[color], [bike].[weight], [bike].[location], [bike].[is_available], AVG([rates].[rate]) AS [rate_avg], [rates].[id] AS [rates.id], [rates].[rate] AS [rates.rate] FROM [bikes] AS [bike] LEFT OUTER JOIN [rates] AS [rates] ON [bike].[id] = [rates].[bikeId] LEFT OUTER JOIN ( [rates] AS [rates] INNER JOIN [users] AS [rates->user] ON [rates].[userId] = [rates->user].[id] AND [rates->user].[login] = N'user' ) ON [bike].[id] = [rates].[bikeId] GROUP BY [bike].[id], [bike].[model], [bike].[photo], [bike].[color], [bike].[weight], [bike].[location], [bike].[is_available];
并且失败:SequelizeDatabaseError: The correlation name 'rates' is specified multiple times in a FROM clause.
如何正确编写查询?我需要Sequelize为第二次连接中使用的rates
表分配另一个别名(并将其列添加到GROUP BY
子句中,但这是下一步)。
答案 0 :(得分:0)
解决方案:
Bike.findAll({
attributes: {include: [[Sequelize.fn('AVG', Sequelize.col('rates.rate')), 'rate_avg']],
},
include: [{
model: Rate,
attributes: []
}, {
model: Rate,
required : false , // 1. just to make sure not making inner join
separate : true , // 2. will run query separately , so your issue will be solved of multiple times
attributes: ['rate'],
include: [{
model: User,
attributes: [],
where: {
login: req.user.login
}
}]
group : [] // 3. <------- This needs to be managed , so please check errors and add fields as per error
}],
group: Object.keys(Bike.rawAttributes).map(key => 'bike.' + key) // group by all fields of Bike model
})
注意:阅读评论
答案 1 :(得分:0)
Sequelize不支持两次通过同一关联进行访问(请参阅here,here和here)。在模型级别,您可以在Bike和Rate之间定义2种不同的关联,但是必须更改模型,添加新的外键等,这是一个非常棘手的解决方案。
顺便说一句,它不能解决您的其他问题,即您仅按Bike分组,然后要选择用户的费率。要解决此问题,您还必须更改分组以包括用户费率。 (请注意,如果用户每辆自行车的费率超过1个,则由于每个用户的费率都要反复对自行车的费率进行平均,因此这也会造成效率低下。)
一种适当的解决方案是使用窗口函数,首先对每辆自行车的费率求平均,然后过滤掉不属于登录用户的所有费率。可能看起来像这样:
SELECT *
FROM (
SELECT bike.*,
users.login AS user_login,
AVG (rates.rate) OVER (PARTITION BY bike.id) AS rate_avg
FROM bike
INNER JOIN rates ON rates.bikeId = bike.id
INNER JOIN users ON rates.userId = users.id
)
WHERE user_login = :req_user_login
不幸的是,据我所知,sequelize当前不支持FROM子句中的子查询,并且不以这种方式使用窗口函数,因此您必须回到原始查询。
答案 2 :(得分:0)
您可以通过添加与该模型相同的额外关联但使用不同的别名 as: 'alias1'
、as: 'alias2'
、... - 所有这些都存在于同一模型中,从而对同一个表进行多个内部联接+ 相同类型的关联。
还在 github 问题上发布了此解决方案:https://github.com/sequelize/sequelize/issues/7754#issuecomment-783404779
例如对于有很多接收者的聊天
关联(根据需要复制)
Chat.hasMany(Receiver, {
// foreignKey: ...
as: 'chatReceiver',
});
Chat.hasMany(Receiver, {
// foreignKey: ...
as: 'chatReceiver2',
});
现在您需要多次包含关联模型,所有模型都具有不同的别名,因此它不会被覆盖。
所以你可以在查询中使用它们,如下所示:
Chat.findAll({
attributes: ["id"],
include: [{
required: true,
model: Receiver,
as: 'chatReceiver', // Alias 1
attributes: [],
where: { userID: 1 }, // condition 1
}, {
required: true,
model: Receiver,
as: 'chatReceiver2', // Alias 2
attributes: [],
where: { userID: 2 }, // condition 2 as needed
}]
});