GraphQl/Sequalize将多个hasMany/BelongTomany组合到单个列表中

GraphQl/Sequalize将多个hasMany/BelongTomany组合到单个列表中,graphql,sequelize.js,Graphql,Sequelize.js,我目前正在做一个项目,让玩家在1v1或2v2的概念中互相玩游戏 因此,我创建了以下两个sequelize类: player.js export class Player extends Model { static init(sequelize, DataTypes) { return super.init( { id: { type: DataTypes.INTEGER, primaryKey: true

我目前正在做一个项目,让玩家在1v1或2v2的概念中互相玩游戏

因此,我创建了以下两个sequelize类:

player.js

export class Player extends Model {
  static init(sequelize, DataTypes) {
    return super.init(
      {
        id: {
          type: DataTypes.INTEGER,
          primaryKey: true
        },

        createdAt: DataTypes.DATE,
        updatedAt: DataTypes.DATE,
        gender: DataTypes.STRING,
        firstName: DataTypes.STRING,
        lastName: DataTypes.STRING
      },
      {
        sequelize
      }
    );
  }

  // Associations
  static associate() {
    this.games1 = this.hasMany(Game, { as: 'player1_team1', foreignKey: 'player1Team1Id' });
    this.games2 = this.hasMany(Game, { as: 'player1_team2', foreignKey: 'player1Team2Id' });
    this.games3 = this.hasMany(Game, { as: 'player2_team1', foreignKey: 'player2Team1Id' });
    this.games4 = this.hasMany(Game, { as: 'player2_team2', foreignKey: 'player2Team2Id' });
  }  
}
export class Game extends Model {
  static init(sequelize, DataTypes) {
    return super.init(
      {
        id: {
          type: DataTypes.INTEGER,
          primaryKey: true,
          autoIncrement: true
        },
        createdAt: DataTypes.DATE,
        updatedAt: DataTypes.DATE,

        playedAt: DataTypes.DATE,

        set1_team1: {
          type: DataTypes.INTEGER,
          allowNull: true
        },
        set1_team2: {
          type: DataTypes.INTEGER,
          allowNull: true
        },

        set2_team1: {
          type: DataTypes.INTEGER,
          allowNull: true
        },
        set2_team2: {
          type: DataTypes.INTEGER,
          allowNull: true
        },

        set3_team1: {
          type: DataTypes.INTEGER,
          allowNull: true
        },
        set3_team2: {
          type: DataTypes.INTEGER,
          allowNull: true
        }
      },
      {
        sequelize
      }
    );
  }

  // Associations
  static associate() {   
    this.player1_team1 = this.belongsTo(Player, {
      as: 'player1_team1',
      foreignKey: 'player1Team1Id'
    });
    this.player1_team2 = this.belongsTo(Player, {
      as: 'player1_team2',
      foreignKey: 'player1Team2Id'
    });
    this.player2_team1 = this.belongsTo(Player, {
      as: 'player2_team1',
      foreignKey: 'player2Team1Id'
    });
    this.player2_team2 = this.belongsTo(Player, {
      as: 'player2_team2',
      foreignKey: 'player2Team2Id'
    });
  }
}
game.js

export class Player extends Model {
  static init(sequelize, DataTypes) {
    return super.init(
      {
        id: {
          type: DataTypes.INTEGER,
          primaryKey: true
        },

        createdAt: DataTypes.DATE,
        updatedAt: DataTypes.DATE,
        gender: DataTypes.STRING,
        firstName: DataTypes.STRING,
        lastName: DataTypes.STRING
      },
      {
        sequelize
      }
    );
  }

  // Associations
  static associate() {
    this.games1 = this.hasMany(Game, { as: 'player1_team1', foreignKey: 'player1Team1Id' });
    this.games2 = this.hasMany(Game, { as: 'player1_team2', foreignKey: 'player1Team2Id' });
    this.games3 = this.hasMany(Game, { as: 'player2_team1', foreignKey: 'player2Team1Id' });
    this.games4 = this.hasMany(Game, { as: 'player2_team2', foreignKey: 'player2Team2Id' });
  }  
}
export class Game extends Model {
  static init(sequelize, DataTypes) {
    return super.init(
      {
        id: {
          type: DataTypes.INTEGER,
          primaryKey: true,
          autoIncrement: true
        },
        createdAt: DataTypes.DATE,
        updatedAt: DataTypes.DATE,

        playedAt: DataTypes.DATE,

        set1_team1: {
          type: DataTypes.INTEGER,
          allowNull: true
        },
        set1_team2: {
          type: DataTypes.INTEGER,
          allowNull: true
        },

        set2_team1: {
          type: DataTypes.INTEGER,
          allowNull: true
        },
        set2_team2: {
          type: DataTypes.INTEGER,
          allowNull: true
        },

        set3_team1: {
          type: DataTypes.INTEGER,
          allowNull: true
        },
        set3_team2: {
          type: DataTypes.INTEGER,
          allowNull: true
        }
      },
      {
        sequelize
      }
    );
  }

  // Associations
  static associate() {   
    this.player1_team1 = this.belongsTo(Player, {
      as: 'player1_team1',
      foreignKey: 'player1Team1Id'
    });
    this.player1_team2 = this.belongsTo(Player, {
      as: 'player1_team2',
      foreignKey: 'player1Team2Id'
    });
    this.player2_team1 = this.belongsTo(Player, {
      as: 'player2_team1',
      foreignKey: 'player2Team1Id'
    });
    this.player2_team2 = this.belongsTo(Player, {
      as: 'player2_team2',
      foreignKey: 'player2Team2Id'
    });
  }
}
然后是GraphQl的以下方案

gql`  
  type Player {
    id: ID!
    firstName: String!
    lastName: String!
    games: [Game]
  }

  type Game {
    id: ID!
    player1_team1: Player!
    player1_team2: Player!
    player2_team1: Player!
    player2_team2: Player!
  }

  type Query {
    player(id: ID!): Player
  }
`
现在,当你查询
玩家时,我试图让你得到所有的游戏,无论他是玩家1\u team1,玩家2\u team2

但我在想如何做到这一点时有点受阻:/

我尝试添加将4个数组组合到我的类中的
getGames()
,但我没有找到如何调用此方法

getGames() {
  return [...this.games1, ...this.games2, ...this.games3, ...this.games4];
}
我尝试搜索一种方法,您可以使用一个别名来查询,该别名组合了4个孩子(player1_team1…),但没有成功(在GraphQl中仍然是新的)

有人能帮我吗?

游戏是一门课。调用
newgame
或类似
Game.create的静态方法生成类的实例。所以我们有

const Game = require('the location of the model')
const game = new Game()
在本例中,静态方法将在
Game
变量上可用,因为它们应用于类,而不是该类的实例。同样,您在类中定义的非静态方法将在实例上可用,而不是在类上可用(即
game
变量)

该方法在两个模型之间创建关联,并返回类的实例。通过这样写:

this.games1 = this.hasMany(Game, { ... })
您正在设置
games1
static属性,因为这是在静态方法中进行的。因此,该属性在类而不是实例上可用。将结果关联对象保存到静态属性可能会有所帮助,但也不是必需的。你可以很容易地做到:

this.hasMany(Game, { ... })
重要的一点是,通过调用
hasMany
,实际上是在类的实例上创建一个getter。在这种情况下,4个getter将根据您提供的别名命名为
getPlayer1_team1
getPlayer2_team1
getPlayer1_team2
getPlayer2_team2

因此,您可以添加如下方法:

async getGames() {
  const [games1, games2, games3, games4] = await Promise.all([
    this.getPlayer1_team1(),
    this.getPlayer1_team2(),
    this.getPlayer2_team1(),
    this.getPlayer2_team2(),
  ])
  return [...this.games1, ...this.games2, ...this.games3, ...this.games4]
}
然后从某个实例调用它:

const player = await Player.findByPk(1)
const games = await Player.getGames()
如果您的模式在
Player
类型上公开了一个
games
字段,您可以在该字段的解析器中执行此操作:

function resolve(parent, args, context, info) {
  return parent.getGames()
}
或者…

您可以在抓取玩家时延迟加载相关模型并获取游戏。这通常比先抓取玩家然后再抓取游戏更有效。因此,在获取播放器时,您可以执行以下操作:

const player = await Player.findByPk(1, {
  include: [
    { as: 'player1_team1', model: Game },
    { as: 'player1_team2', model: Game },
    { as: 'player2_team1', model: Game },
    { as: 'player2_team2', model: Game },
  ]
})
注意:重要的是要包含与定义关联时使用的值相同的
。生成的
player
变量现在将具有关联游戏的4个属性(
player1\u team1
player1\u team2
,等等)

如果您在获取Player实例时像这样懒洋洋地加载关联的游戏,现在可以执行类似操作来解析GraphQL中的
Games
字段:

function resolve(parent, args, context, info) {
  return [
    ...parent.player1_team1,
    ...parent.player1_team2,
    ...parent.player2_team1,
    ...parent.player2_team2,
  ]
}

另外,您可能应该将初始化模型的映射传递给
associate
方法,这样就不必处理循环依赖关系。