【问题标题】:Querying association tables in Sequelize在 Sequelize 中查询关联表
【发布时间】:2016-09-30 22:55:30
【问题描述】:

我有两个表(users 和 games)通过关联表 (game_players) 连接,创建了多对多关系:

models.Game.belongsToMany(models.User, { through: models.GamePlayer, as: 'players' });
models.User.belongsToMany(models.Game, { through: models.GamePlayer, foreignKey: 'user_id' });

除了外键user_id 和game_id 之外,game_players 还有一些额外的列用于链接特定的数据:

sequelize.define('game_player', {
    isReady: {
        defaultValue: false,
        type: Sequelize.BOOLEAN,
        field: 'is_ready'
    },
    isDisabled: {
        defaultValue: false,
        type: Sequelize.BOOLEAN,
        field: 'is_disabled'
    },
    powerPreferences: {
        type: Sequelize.TEXT,
        field: 'power_preferences'
    },
    power: {
        type: Sequelize.STRING(2),
        defaultValue: '?'
    }
}, {
    underscored: true
});

假设我想获取一个游戏并急切地加载活跃玩家。这是我的第一次尝试:

db.models.Game.findAll({
    include: [{
        model: db.models.User,
        as: 'players',
        where: { 'game_player.isDisabled': false }
    }]
}).nodeify(cb);

这会生成以下 SQL,它会抛出错误 Column players.game_player.isDisabled does not exist:

SELECT "game"."id", 
   "game"."name", 
   "game"."description", 
   "game"."variant", 
   "game"."status", 
   "game"."move_clock"                       AS "moveClock", 
   "game"."retreat_clock"                    AS "retreatClock", 
   "game"."adjust_clock"                     AS "adjustClock", 
   "game"."max_players"                      AS "maxPlayers", 
   "game"."created_at", 
   "game"."updated_at", 
   "game"."gm_id", 
   "game"."current_phase_id", 
   "players"."id"                            AS "players.id", 
   "players"."email"                         AS "players.email", 
   "players"."temp_email"                    AS "players.tempEmail", 
   "players"."password"                      AS "players.password", 
   "players"."password_salt"                 AS "players.passwordSalt", 
   "players"."action_count"                  AS "players.actionCount", 
   "players"."failed_action_count"           AS "players.failedActionCount", 
   "players"."created_at"                    AS "players.created_at", 
   "players"."updated_at"                    AS "players.updated_at", 
   "players.game_player"."is_ready"          AS 
   "players.game_player.isReady", 
   "players.game_player"."is_disabled"       AS 
   "players.game_player.isDisabled", 
   "players.game_player"."power_preferences" AS 
   "players.game_player.powerPreferences", 
   "players.game_player"."power"             AS "players.game_player.power", 
   "players.game_player"."created_at"        AS 
   "players.game_player.created_at", 
   "players.game_player"."updated_at"        AS 
   "players.game_player.updated_at", 
   "players.game_player"."game_id"           AS 
   "players.game_player.game_id", 
   "players.game_player"."user_id"           AS 
   "players.game_player.user_id" 
FROM   "games" AS "game" 
   INNER JOIN ("game_players" AS "players.game_player" 
               INNER JOIN "users" AS "players" 
                       ON "players"."id" = "players.game_player"."user_id") 
           ON "game"."id" = "players.game_player"."game_id" 
              AND "players"."game_player.isdisabled" = false;

显然,Sequelize 用不正确的引号将我的约束别名包装起来:'players'.'game_player.isdisabled' 应该是 'players.game_player'.isdisabled。如何修改上面的 Sequelize 代码以正确查询此列?

【问题讨论】:

    标签: javascript sql sequelize.js


    【解决方案1】:

    我知道了,但只能通过手动浏览存储库的已关闭票证并找到#4880。

    使用未开箱即用的连接表列的子句可以包装在$ 中。老实说,我不明白它的魔力,因为我发誓我没有看到任何关于它的文档。修改我上面的查询实现了我想要的:

    db.models.Game.findAll({
        include: [{
            model: db.models.User,
            as: 'players',
            where: { '$players.game_player.is_disabled$': false }
        }]
    }).nodeify(cb);
    

    【讨论】:

    【解决方案2】:

    找了一圈,发现through.where也可以用:

    db.models.Game.findAll({
        include: [{
            model: db.models.User,
            as: 'players',
            through: {  where: { isDisabled: false } }
        }]
    })
    

    参考:
    Is it possible to filter a query by the attributes in the association table with sequelize?
    Eager loading with Many-to-Many relationships

    【讨论】:

    • 这是对我来说真正有效的答案,感觉远没有公认的那么神奇。
    【解决方案3】:

    您的查询应该在带有“where”条件的连接表上,然后您应该使用“include”子句来包含其他两个模型,如下所示:

        db.models.GamePlayer.findAll({
            where: {isDisabled: false},
            attributes: [],
            include: [models.User, models.Game]
        }).then(function(result){
            ....
        });
    

    【讨论】:

    • 这在理论上可行,但它以不合逻辑的结构返回数据。我想要一款游戏及其玩家;这更多的是“玩家和他们玩的游戏”。
    猜你喜欢
    • 2016-12-19
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 2016-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多