Joining same table multiple times with Sequelize

Ale*_*kin 5 node.js sequelize.js

I have the following models:

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);
Run Code Online (Sandbox Code Playgroud)

And I'd like to select bikes with their average rates, plus rates of the current user for each bike:

    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
    })
Run Code Online (Sandbox Code Playgroud)

It constructs the following query: 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];

And fails: SequelizeDatabaseError: The correlation name 'rates' is specified multiple times in a FROM clause.

How do I write the query right? I need Sequelize to assign another alias to the rates table used in the 2nd join (and add its columns to the GROUP BY clause, but that's the next step).

Viv*_*shi 1

解决方案 :

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
})
Run Code Online (Sandbox Code Playgroud)

注意:阅读评论