这是我的typeDefs
:
const typeDefs: string = `
type Book {
id: ID!
title: String
authorId: ID!
author: User
}
type User {
id: ID!
name: String
}
type Query {
books: [Book]!
}
`;
export { typeDefs };
resolvers
:
import { IResolvers } from 'graphql-tools';
import { IBook } from './db';
const resolvers1: IResolvers = {
Query: {
books: (_, args, { db }): Promise<IBook[]> => {
return db.books.map(book => {
book.author = db.users.find(user => book.authorId === user.id);
return book;
});
}
}
};
const resolvers2: IResolvers = {
Query: {
books: (_, args, { db }): Promise<IBook[]> => {
return db.books;
}
},
Book: {
author: (book, args, { db }) => {
return db.users.find(user => book.authorId === user.id);
}
}
};
export { resolvers1, resolvers2 };
在resolvers1
中,它解析Book
的所有字段。 (将author
字段添加到book
)
在resolvers2
内,它解析独立解析器中Book
的每个字段。
我发现resovlers1
和resolvers2
都可以正常工作。我可以得到如下正确的响应:
{
"data": {
"books": [
{
"id": "02wDZbBuMi",
"title": "Ea repellendus",
"authorId": "hhP2TtobM",
"author": {
"id": "hhP2TtobM",
"name": "Mrs. Destiney Kerluke"
}
},
{
"id": "tC3uPfKfUZ",
"title": "Consectetur fugit",
"authorId": "k9IHZAtld8",
"author": {
"id": "k9IHZAtld8",
"name": "Mr. Rene Heidenreich"
}
}
]
}
}
它们之间有什么区别?这两种方法正确吗?如果没有,为什么?
答案 0 :(得分:1)
resolver2
更好,因为如果您的请求中不包含author
,它不会对数据库进行无用的调用。
答案 1 :(得分:1)
resolver1
是性能复杂度的折衷。解析器一的主要论据是数据库通常具有resolver2
无法使用的联接。例如,书籍+作者查询可以用单个SQL语句表示。即使使用Dataloader,与版本2相比,这也是巨大的性能优势。现在有人可能会争辩说,我们甚至不知道是否需要作者字段。但是我们可以使用resolveInfo
参数来了解这一点。可以编写一个函数来快速检查resolveInfo并告诉我们子选择中是否存在字段:
hasSelection(fieldName: string, resolveInfo: GraphQLResolveInfo): boolean
然后我们可以使用此功能检查是否应该进行联接。
books: (_, args, { db }, resolveInfo): Promise<IBook[]> => {
if (hasSelection('author', resolveInfo)) {
// Just an example, there is some more transformation needed
return db.query('SELECT ... FROM book JOIN author ON book.authorId = author.id');
}
return db.query('SELECT ... FROM book');
}
这可能会提高性能两倍。实际上,很多公司都这样做,因为有时性能是关键。如果示例变得更加复杂,那么复杂性就会大大增加,如果不首先将其确定为瓶颈,我就不会进行这种优化。另一方面,有许多项目在“本机GraphQL”上工作,这意味着他们正在将GraphQL查询直接转换为数据库查询。