GraphQL (Apollo)、Sequelize、MySQL & 使用非标准外键

GraphQL (Apollo), Sequelize, MySQL & using non-standard foreign keys

我正在使用 Apollo、Sequelize、Node 和 MySQL 在 GraphQL 服务器上工作。数据由视频和团队(在那些视频中)组成。我还使用非标准外键将团队连接到特定视频(数据库 table Teams 有一个名为 'inVideo' 的字段,而不是默认的 'VideoId' 字段)。创建视频和团队以及查询特定的(带有 id)或所有项目都不是问题。但是,当我尝试查询属于特定视频的团队时(通过提供特定视频的 ID),后端的 SQL SELECT 查询包含一个额外的字段名称,这是默认的 foreign键构造“VideoId”,由于该字段在数据库中不存在,查询失败。

这是创建 Teams table 的迁移文件(注意 inVideo 字段定义):

'use strict';
module.exports = {
  async up(queryInterface, Sequelize) {
    await queryInterface.createTable('Teams', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      inVideo: {
        allowNull: false,
        type: Sequelize.INTEGER
      },
      name: {
        allowNull: false,
        type: Sequelize.STRING
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
  },
  async down(queryInterface, Sequelize) {
    await queryInterface.dropTable('Teams');
  }
};

这里是Sequelize的团队模型定义(注意belongsTo中的foreignKey定义)

'use strict';
const {
  Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
  class Team extends Model {
    static associate(models) {
      Team.belongsTo(models.Video, { foreignKey: "inVideo" })
    }
  }
  Team.init({
    name: {
      allowNull: false,
      type: DataTypes.STRING
    }
  }, {
    sequelize,
    modelName: 'Team',
  });
  return Team;
};

在数据库中生成视频的迁移文件table没有什么特别的,但是这里是视频的Sequelize模型文件(因为我在该模型中添加了hasMany关系):

'use strict';
const {
  Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
  class Video extends Model {
    static associate(models) {
      Video.hasMany(models.Team)
    }
  }
  Video.init({
    videoUrl: {
      allowNull: false,
      type: DataTypes.STRING
    }
  }, {
    sequelize,
    modelName: 'Video',
  });
  return Video;
};

然后是 GraphQL 模式定义

const { gql } = require('apollo-server');
const typeDefs = gql`
  type Video {
    id: Int!
    videoUrl: String!
    teams: [Team!]!
  }

  type Team {
    id: Int!
    name: String!
    video: Video!
  }

  type Query {
    teams(inVideo: Int!): [Team!]!
  }

  type Mutation {
    createVideo(videoUrl: String!): Video!
    createTeam(inVideo: Int!, name: String!): Team!
  }
`;
module.exports = typeDefs;

最后是服务器的解析器定义:

const resolvers = {
  Query: {
    async teams(root, { inVideo }, { models }) {
      return models.Team.findAll({
        where: {
          inVideo: inVideo
        }
      });
    },
  },
  Mutation: {
    async createVideo(root, { videoUrl }, { models }) {
      return models.Video.create({ videoUrl });
    },
    async createTeam( root, { inVideo, name }, { models }) {
      return models.Team.create({ inVideo, name });
    },
  },
  Video: {
    async teams(video) {
      return video.getTeams();
    },
  },
  Team: {
    async video(team) {
      return team.getVideo();
    },
  },  
};
module.exports = resolvers;

如前所述,创建视频和团队工作正常,数据库中的数据正确。但是,当我尝试查询服务器以获取某个视频的团队时,SQL SELECT 子句如下:

SELECT `id`, `name`, `createdAt`, `updatedAt`, `inVideo`, `VideoId` FROM `Teams` AS `Team` WHERE `Team`.`inVideo` = 1;

VideoId 字段不应该在那里,因为它不存在于数据库中(关系信息存储在 inVideo 字段中)。

我怎样才能摆脱这种行为? (我认为 belongsTo 方法调用中的 foreignKey 选项可以解决这个问题)

此外,我使用关系定义关系/查询团队的方式(使用 findAll 的 where-option)可能不正确。有更好的方法吗?

当您使用自己的显式外键字段时,不要忘记为两端的关联指明它:

Video.hasMany(models.Team, { foreignKey: "inVideo" })

否则,Sequelize 将使用默认外键名称ModelName+Id(在本例中为VideoId)。