GraphQL 从 MySQL 连接查询返回 null

Posted

技术标签:

【中文标题】GraphQL 从 MySQL 连接查询返回 null【英文标题】:GraphQL returning null from MySQL join query 【发布时间】:2021-05-10 03:13:25 【问题描述】:

我有一个小型 Node 项目(基于位置的简单猜谜游戏)来服务于 React 前端。它使用 Apollo 服务器从 AWS RDS mysql 数据库中检索数据,并使用 knex 作为查询构建器。我可以成功地从单个表中检索数据,但是当查询包含连接时,graphql 中的子对象始终为空。

当我在本地访问节点服务器并查询 guess 的数据时,我有 guess 数据,但关联的 user如图所示,问题数据始终为空。

graphql_issue

这里是代码 - 我已经删除了一些运行正常的查询的多余代码。

数据库

CREATE TABLE `question` (
  `id` int NOT NULL AUTO_INCREMENT,
  `lat` float NOT NULL,
  `lng` float NOT NULL,
  `question` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE `guess` (
  `id` int NOT NULL AUTO_INCREMENT,
  `lat` float NOT NULL,
  `lng` float NOT NULL,
  `question_id` int NOT NULL,
  `user_id` int NOT NULL,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `question_id` (`question_id`),
  CONSTRAINT `guess_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
  CONSTRAINT `guess_ibfk_2` FOREIGN KEY (`question_id`) REFERENCES `question` (`id`)
);

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(11) NOT NULL,
  `icon` varchar(11) NOT NULL,
  `score` int NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
);

Apollo 服务器应用程序

index.js

const  ApolloServer  = require("apollo-server");
const typeDefs = require("./schema");
const mapDatabase = require("./datasources/map");
const resolvers = require("./resolver");

const knexConfig = 
    client: "mysql",
    connection: 
        host: "my-server",
        user: "my-username",
        password: "my-password",
        database: "db-name",
    ,
;

const server = new ApolloServer(
    typeDefs,
    resolvers,
    dataSources: () => (
        mapDatabase: new mapDatabase(knexConfig),
    ),
);

// The `listen` method launches a web server.
server.listen().then(( url ) => 
    console.log(`Server ready at $url`);
);

schema.js

const  gql  = require("apollo-server");

const typeDefs = gql`
    type User 
        id: ID!
        username: String
        icon: String
        score: Int
    
    type Question 
        id: ID!
        lat: Float
        lng: Float
        question: String
    
    type Guess 
        id: ID!
        lat: Float
        lng: Float
        question: Question
        user: User
    
    type Query 
        guesses(question: Int!): [Guess]
    
`;

module.exports = typeDefs;

resolver.js

module.exports = 
    Query: 
        guesses: (_,  question ,  dataSources ) =>
            dataSources.mapDatabase.getGuessesByQuestion(question),
    ,
;

datasources/map.js

const  SQLDataSource  = require("datasource-sql");

class MapDatabase extends SQLDataSource 
    getGuessesByQuestion(question) 
        return this.knex
            .select("*")
            .from("guess AS g")
            .leftJoin("user AS u", "u.id", "g.user_id")
            .leftJoin("question AS q", "q.id", "g.question_id")
            .where("g.question_id", "=", question);
    

作为健全性检查,我在数据库上运行查询以确保获得相关结果并按预期恢复所有内容。

SELECT * FROM guess g
LEFT JOIN user u ON u.id = g.user_id
LEFT JOIN question q ON a.id = g.question_id
WHERE g.question_id = 1;

【问题讨论】:

缺少解析器...关注有关 graphql 服务器中关系的一些教程 【参考方案1】:

问题在于您的查询返回平面数据,而您的 GraphQL 隐式解析器需要嵌套对象结构。例如。 knext 会返回如下内容:


  id: 1,
  lat: 89.4,
  lon: -12.6,
  user_id: 2,
  username: "user",
  icon: "x",
  score: 3

但是你需要这样的东西才能让解析器“正常工作”。


  id: 1,
  lat: 89.4,
  lon: -12.6,
  user: 
    id: 2,
    username: "user",
    icon: "x",
    score: 3
  

请记住:如果您不将解析器传递给字段,它将使用默认解析器尝试访问对象的字段名称属性。因此user 字段将具有以下默认解析器:

parent => parent.user

在扁平结构中,没有字段,因此返回undefined -> 查询返回该字段的null。 在嵌套结构中,它将返回一个有效的用户对象。

您可以使用 SQL JSON 函数或为Guess.user 实现自定义解析器来构建结果:

module.exports = 
  Query: 
    guesses: (_,  question ,  dataSources ) =>
      dataSources.mapDatabase.getGuessesByQuestion(question),
  ,
  Guess: 
    user: (parent) => (
      id: parent.user_id,
      username: parent.username,
      icon: parent.icon,
      score: parent.score
    ),
  
;

【讨论】:

以上是关于GraphQL 从 MySQL 连接查询返回 null的主要内容,如果未能解决你的问题,请参考以下文章

查询不会通过 GraphQL 从 DynamoDB 返回某些项目

Nestjs / GraphQL - Playground 为查询返回 Null 错误。我的解析器?

返回 node-mysql 中 graphql 解析器函数的 mysql 查询

当 GraphQL 查询只需要返回对象的某些字段时,为啥 MySQL/Sequelize 会执行全选查询?

AWS Amplify GraphQL - 一对多连接在查询时返回空列表

MySQL 查询性能 - 查询/架构/索引?