Sim*_*mon 12 javascript graphql graphql-js
我正在使用DataLoader将请求/查询一起批处理.在我的加载器功能中,我需要知道所请求的字段,以避免有一个SELECT * FROM query而是SELECT field1, field2, ... FROM query...
使用DataLoader传递resolveInfo所需的最佳方法是什么?(我resolveInfo.fieldNodes用来获取请求的字段)
目前,我正在做这样的事情:
await someDataLoader.load({ ids, args, context, info });
Run Code Online (Sandbox Code Playgroud)
然后在实际的loaderFn中:
const loadFn = async options => {
const ids = [];
let args;
let context;
let info;
options.forEach(a => {
ids.push(a.ids);
if (!args && !context && !info) {
args = a.args;
context = a.context;
info = a.info;
}
});
return Promise.resolve(await new DataProvider().get({ ...args, ids}, context, info));};
Run Code Online (Sandbox Code Playgroud)
但正如你所看到的那样,这很黑,而且感觉并不好......
有谁知道我怎么能做到这一点?
Her*_*rku 14
我不确定这个问题是否有一个很好的答案,因为 Dataloader 不是为这个用例制作的,但我与 Dataloader 进行了广泛的合作,编写了类似的实现并探索了其他编程语言的类似概念。
让我们了解为什么 Dataloader 不是为这个用例制作的,以及我们如何仍然使它工作(大致就像你的例子一样)。
Dataloader 是为简单的键值查找而设计的。这意味着给定一个像 ID 这样的键,它会在它后面加载一个值。为此,它假定 ID 后面的对象将始终相同,直到它失效。这是启用数据加载器功能的单一假设。没有它,Dataloader的三个关键功能将不再起作用:
如果我们想最大限度地发挥 Dataloader 的功能,这将引导我们遵循以下两个重要规则:
两个不同的实体不能共享同一个 key,否则我们可能会返回错误的实体。这听起来微不足道,但它不在您的示例中。假设我们要加载具有 ID1和字段的用户id和name。稍后(或同时)我们想用 ID1和字段id以及email. 从技术上讲,它们是两个不同的实体,它们需要具有不同的密钥。
同一个实体应该始终拥有相同的密钥。再次听起来微不足道,但实际上不在示例中。用户ID为1和字段id和name应该是相同的,与用户ID1和字段name和id(通知的顺序)。
简而言之,密钥需要具有唯一标识实体所需的所有信息,但仅此而已。
await someDataLoader.load({ ids, args, context, info });
Run Code Online (Sandbox Code Playgroud)
在您的问题中,您已向 Dataloader 提供了更多内容作为关键。首先,我不会将 args 和 context 放入键中。当上下文发生变化时,您的实体是否会发生变化(例如,您现在正在查询不同的数据库)?可能是的,但是你想在你的数据加载器实现中考虑到这一点吗?相反,我建议为每个请求创建新的数据加载器,如文档中所述。
整个请求信息应该在密钥中吗?不,但我们需要请求的字段。除此之外,您提供的实现是错误的,并且在使用两个不同的解析信息调用加载程序时会中断。您只设置了第一次调用的解析信息,但实际上每个对象的解析信息可能不同(想想上面的第一个用户示例)。最终我们可以实现以下数据加载器的实现:
await someDataLoader.load({ ids, args, context, info });
Run Code Online (Sandbox Code Playgroud)
这是一个可靠的实现,但它有一些弱点。首先,如果我们在同一个批处理请求中有不同的字段需求,我们就会过度获取很多字段。其次,如果我们1[id,name]从缓存键函数中获取了一个带有键的实体,我们也可以回答(至少在 JavaScript 中)键1[id]和1[name]该对象。在这里,我们可以构建一个可以提供给 Dataloader 的自定义地图实现。知道关于我们的缓存的这些事情就足够聪明了。
我们看到这确实是一个复杂的问题。我知道它经常被列为 GraphQL 的一个好处,即您不必为每个查询从数据库中获取所有字段,但事实是,实际上这很少值得麻烦。不要优化不慢的东西。甚至是慢,是瓶颈吗?
我的建议是:编写简单的 Dataloaders 来简单地获取所有(需要的)字段。如果您有一个客户端,很可能对于大多数实体,客户端无论如何都会获取所有字段,否则它们将不会成为您 API 的一部分,对吗?然后使用诸如查询内省之类的东西来衡量慢查询,然后找出到底哪个字段是慢的。然后您只优化缓慢的事情(例如,请参阅我在此处优化单个用例的答案)。如果您是大型电子商务平台,请不要为此使用 Dataloader。构建更智能的东西,不要使用 JavaScript。