在Sequelize中优化对相关表的查询

时间:2020-02-24 00:08:17

标签: javascript mysql sql node.js sequelize.js

我想知道是否有更好的方法来获得以下结果:使用通过多对多关系连接的表中的值过滤行列表。 在我的示例案例中,歌曲带有某些乐器。

这是我的歌曲模特:

module.exports = function(sequelize, DataTypes) {
    var Song = sequelize.define('songs', {
        id: {
            type: DataTypes.INTEGER(10).UNSIGNED,
            allowNull: false,
            primaryKey: true,
            autoIncrement: true
        },
        title: {
            type: DataTypes.STRING(50),
            allowNull: false
        },
    }, {
        tableName: 'songs',
        timestamps: false
    });

    Song.associate = function (models) {
        Song.belongsToMany(models.instruments, {through: 'songs_instruments', foreignKey: 'song_id'})
    };

    return Song
};

这是我的乐器模型:

module.exports = function(sequelize, DataTypes) {
    var Instrument = sequelize.define('instruments', {
        id: {
            type: DataTypes.INTEGER(10).UNSIGNED,
            allowNull: false,
            primaryKey: true,
            autoIncrement: true
        },
        name: {
            type: DataTypes.STRING(50),
            allowNull: false
        }
    }, {
        tableName: 'instruments',
        timestamps: false,
    });

    Instrument.associate = function (models) {
        Instrument.belongsToMany(models.songs, {through: 'songs_instruments', foreignKey: 'instrument_id'})
    };

    return Instrument
};

这是联接表的模型:

module.exports = function(sequelize, DataTypes) {
    return sequelize.define('songs_instruments', {
        id: {
            type: DataTypes.INTEGER(10).UNSIGNED,
            allowNull: false,
            primaryKey: true,
            autoIncrement: true
        },
        song_id: {
            type: DataTypes.INTEGER(10).UNSIGNED,
            allowNull: false,
            references: {
                model: 'songs',
                key: 'id'
            }
        },
        instrument_id: {
            type: DataTypes.INTEGER(10).UNSIGNED,
            allowNull: false,
            references: {
                model: 'instruments',
                key: 'id'
            }
        }
    }, {
        tableName: 'songs_instruments',
        timestamps: false
    });
};

这是我当前的获取方式(args['instruments']包含我要为其过滤歌曲的乐器列表):

const instruments = await db.instruments.findAll({
    where: {name: args['instruments']}
})

const songs_instruments = await db.songs_instruments.findAll({
    where: {instrument_id: instruments.map(instrument => instrument.id)}
})

const songs = await db.songs.findAll({
    where: {id: songs_instruments.map(song => song.song_id)}
})
return songs

虽然这可以正常工作,但最终我得到了我期望的结果,我不禁想知道是否存在一种更有效的查询数据库的方法,因为这样做会导致总共三个查询要执行:

Executing (default): SELECT `id`, `name` FROM `instruments` AS `instruments` WHERE `instruments`.`name` IN ('Vocals', 'Trumpet', 'Guitar');
Executing (default): SELECT `id`, `song_id`, `instrument_id` FROM `songs_instruments` AS `songs_instruments` WHERE `songs_instruments`.`instrument_id` IN (1, 3, 7);
Executing (default): SELECT `id`, `title` FROM `songs` AS `songs` WHERE `songs`.`id` IN (1, 1, 2, 2, 3, 3);

我对Sequelize相当陌生,因此我实现目标的方式可能不正确/次优。

2 个答案:

答案 0 :(得分:1)

哦,我完全错过了..太晚了..是的,你可以这样做..添加如下所示的别名作为此连接的名称,并在歌曲中执行以下相同的操作:'instruments'... you don'不需要获取联接记录。

Instrument.associate = function (models) {
        Instrument.belongsToMany(models.songs, {through: 'songs_instruments', as: 'songs', foreignKey: 'instrument_id', otherKey: 'song_id'})
    };

const instruments = await db.instruments.findAll({
    where: {name: args['instruments']},
    {
     include: [{
        model: db.songs,
        as: 'songs', 
        through: db.songs_instruments,
      }]
   }
});

或类似以下内容的内容...

const songs = await db.songs.findAll({
          include: [{
            model: db.instruments,
            as: 'instruments', 
            through: db.songs_instruments,
            where: {name: args['instruments']}
          }],
        });

答案 1 :(得分:0)

看起来您正在使用数据加载器,并且对三个查询进行了批处理..我认为您都很好...您显然在利用带有sequelize的模型设置,因此它必须具有通用性,我看不到这里有问题

相关问题