使用 Dataloader 处理 GraphQL 字段参数?
handling GraphQL field arguments using Dataloader?
我想知道在使用 Dataloader 时如何最好地处理 GraphQL 字段参数方面是否存在任何共识。 Dataloader 需要的 batchFn
批处理函数期望接收 Array<key>
和 returns 一个 Array<Promise>
,通常只需要调用 load( parent.id )
where parent
是给定字段的解析器的第一个参数。在大多数情况下,这很好,但是如果您需要为嵌套字段提供参数怎么办?
例如,假设我有一个 SQL 数据库,其中 table 用于 Users
、Books
,以及一个名为 [=23] 的关系 table =] 表示 Users:Books.
之间的 1:many 关系
我可能会 运行 以下查询,以查看所有用户都读过哪些书:
query {
users {
id
first_name
books_read {
title
author {
name
}
year_published
}
}
}
假设 context
中有一个 BooksReadLoader
可用,这样 books_read
的解析器可能如下所示:
const UserResolvers = {
books_read: async function getBooksRead( user, args, context ) {
return await context.loaders.booksRead.load( user.id );
}
};
BooksReadLoader
的批量加载函数会 async
调用数据访问层方法,这会 运行 一些 SQL 像:
SELECT B.* FROM Books B INNER JOIN BooksRead BR ON B.id = BR.book_id WHERE BR.user_id IN(?);
我们将从结果行创建一些 Book
个实例,按 user_id
分组,然后 return keys.map(fn)
以确保我们将正确的书籍分配给每个 user_id
加载程序缓存中的键。
现在假设我向 books_read
添加一个参数,要求用户阅读 1950 年之前出版的所有书籍:
query {
users {
id
first_name
books_read(published_before: 1950) {
title
author {
name
}
year_published
}
}
}
理论上,我们可以 运行 相同的 SQL 语句,并在解析器中处理参数:
const UserResolvers = {
books_read: async function getBooksRead( user, args, context ) {
const books_read = await context.loaders.booksRead.load( user.id );
return books_read.filter( function ( book ) {
return book.year_published < args.published_before;
});
}
};
但是,这并不理想,因为我们仍在从 Books
table 中获取潜在的大量行,而实际上可能只有少数行满足参数。执行此 SQL 语句会更好:
SELECT B.* FROM Books B INNER JOIN BooksRead BR ON B.id = BR.book_id WHERE BR.user_id IN(?) AND B.year_published < ?;
我的问题是,通过 new DataLoader( batchFn[, options] )
提供的 cacheKeyFn
选项是否允许传递字段的参数以在数据访问层中构造动态 SQL 语句?我已经查看了 https://github.com/graphql/dataloader/issues/75 but I'm still unclear if cacheKeyFn
is the way to go. I'm using apollo-server-express
. There is this other SO question: ,但没有答案,而且我很难找到与此相关的其他来源。
谢谢!
将 id 和 params 作为单个对象传递给加载函数,如下所示:
const UserResolvers = {
books_read: async function getBooksRead( user, args, context ) {
return context.loaders.booksRead.load({id: user.id, ...args});
}
};
然后让批量加载函数找出如何以最佳方式满足它。
您还需要为对象的构造做一些记忆,否则数据加载器的缓存将无法正常工作(我认为它基于身份而不是深度平等工作)。
我想知道在使用 Dataloader 时如何最好地处理 GraphQL 字段参数方面是否存在任何共识。 Dataloader 需要的 batchFn
批处理函数期望接收 Array<key>
和 returns 一个 Array<Promise>
,通常只需要调用 load( parent.id )
where parent
是给定字段的解析器的第一个参数。在大多数情况下,这很好,但是如果您需要为嵌套字段提供参数怎么办?
例如,假设我有一个 SQL 数据库,其中 table 用于 Users
、Books
,以及一个名为 [=23] 的关系 table =] 表示 Users:Books.
我可能会 运行 以下查询,以查看所有用户都读过哪些书:
query {
users {
id
first_name
books_read {
title
author {
name
}
year_published
}
}
}
假设 context
中有一个 BooksReadLoader
可用,这样 books_read
的解析器可能如下所示:
const UserResolvers = {
books_read: async function getBooksRead( user, args, context ) {
return await context.loaders.booksRead.load( user.id );
}
};
BooksReadLoader
的批量加载函数会 async
调用数据访问层方法,这会 运行 一些 SQL 像:
SELECT B.* FROM Books B INNER JOIN BooksRead BR ON B.id = BR.book_id WHERE BR.user_id IN(?);
我们将从结果行创建一些 Book
个实例,按 user_id
分组,然后 return keys.map(fn)
以确保我们将正确的书籍分配给每个 user_id
加载程序缓存中的键。
现在假设我向 books_read
添加一个参数,要求用户阅读 1950 年之前出版的所有书籍:
query {
users {
id
first_name
books_read(published_before: 1950) {
title
author {
name
}
year_published
}
}
}
理论上,我们可以 运行 相同的 SQL 语句,并在解析器中处理参数:
const UserResolvers = {
books_read: async function getBooksRead( user, args, context ) {
const books_read = await context.loaders.booksRead.load( user.id );
return books_read.filter( function ( book ) {
return book.year_published < args.published_before;
});
}
};
但是,这并不理想,因为我们仍在从 Books
table 中获取潜在的大量行,而实际上可能只有少数行满足参数。执行此 SQL 语句会更好:
SELECT B.* FROM Books B INNER JOIN BooksRead BR ON B.id = BR.book_id WHERE BR.user_id IN(?) AND B.year_published < ?;
我的问题是,通过 new DataLoader( batchFn[, options] )
提供的 cacheKeyFn
选项是否允许传递字段的参数以在数据访问层中构造动态 SQL 语句?我已经查看了 https://github.com/graphql/dataloader/issues/75 but I'm still unclear if cacheKeyFn
is the way to go. I'm using apollo-server-express
. There is this other SO question:
谢谢!
将 id 和 params 作为单个对象传递给加载函数,如下所示:
const UserResolvers = {
books_read: async function getBooksRead( user, args, context ) {
return context.loaders.booksRead.load({id: user.id, ...args});
}
};
然后让批量加载函数找出如何以最佳方式满足它。
您还需要为对象的构造做一些记忆,否则数据加载器的缓存将无法正常工作(我认为它基于身份而不是深度平等工作)。