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 会执行全选查询?