在一个解析器 V.S 中解析所有字段。每个解析器中的解析字段
Resolve all fields in one resolver V.S. resolve field in each resolver
这是我的 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"
}
}
]
}
}
它们有什么区别?这两种方式正确吗?如果不是,为什么?
resolver2
更好,因为如果您不在请求中包含 author
,它不会对数据库进行无用的调用。
resolver1
是复杂性与性能的权衡。解析器一的主要论点是数据库通常具有 resolver2
无法使用的连接。例如,书 + 作者查询可以用单个 SQL 语句表示。这是一个 巨大的 性能优势,即使使用 Dataloader 也比版本 2 更好。现在有人可能会争辩说我们甚至不知道是否需要 author 字段。但是我们可以使用 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');
}
这可能会提高两倍的性能。实际上有很多公司这样做,因为有时性能很关键。如果示例变得更复杂,那么复杂性会显着增加,如果不首先将其确定为瓶颈,我不会进行此类优化。另一方面,有很多项目在 "native GraphQL" 上工作,这意味着他们正在将 GraphQL 查询直接转换为数据库查询。
这是我的 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"
}
}
]
}
}
它们有什么区别?这两种方式正确吗?如果不是,为什么?
resolver2
更好,因为如果您不在请求中包含 author
,它不会对数据库进行无用的调用。
resolver1
是复杂性与性能的权衡。解析器一的主要论点是数据库通常具有 resolver2
无法使用的连接。例如,书 + 作者查询可以用单个 SQL 语句表示。这是一个 巨大的 性能优势,即使使用 Dataloader 也比版本 2 更好。现在有人可能会争辩说我们甚至不知道是否需要 author 字段。但是我们可以使用 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');
}
这可能会提高两倍的性能。实际上有很多公司这样做,因为有时性能很关键。如果示例变得更复杂,那么复杂性会显着增加,如果不首先将其确定为瓶颈,我不会进行此类优化。另一方面,有很多项目在 "native GraphQL" 上工作,这意味着他们正在将 GraphQL 查询直接转换为数据库查询。