【问题标题】:GraphQL returning null from MySQL join queryGraphQL 从 MySQL 连接查询返回 null
【发布时间】: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 服务器中关系的一些教程

标签: mysql node.js graphql apollo-server


【解决方案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
    }),
  }
};

【讨论】:

    猜你喜欢
    • 2019-06-14
    • 2020-01-07
    • 1970-01-01
    • 1970-01-01
    • 2017-01-01
    • 2020-01-15
    • 2021-01-15
    • 2020-03-01
    相关资源
    最近更新 更多