作者:SuperBaby蜜 | 来源:互联网 | 2022-12-02 23:55
为了执行类似连接的操作,我们可以同时使用GraphQL和Mongoose来实现这一目的。
在问任何问题之前,我想举一个下面的“任务/活动”示例(此代码没有经过测试,仅出于示例的目的而给出):
Task {
_id,
title,
description,
activities: [{ //Of Activity Type
_id,
title
}]
}
在猫鼬中,我们可以使用populate方法检索与任务相关的活动,如下所示:
const task = await TaskModel.findbyId(taskId).populate('activities');
使用GraphQL和Dataloader,我们可以得到类似以下结果:
const DataLoader = require('dataloader');
const getActivitiesByTask = (taskId) => await ActivityModel.find({task: taskId});
const dataloaders = () => ({
activitiesByTask: new DataLoader(getActivitiesByTask),
});
// ...
// SET The dataloader in the context
// ...
//------------------------------------------
// In another file
const resolvers = {
Query: {
Task: (_, { id }) => await TaskModel.findbyId(id),
},
Task: {
activities: (task, _, context) => context.dataloaders.activitiesByTask.load(task._id),
},
};
我试图查看是否有文章说明哪种方法在性能,资源枯竭等方面更好,但是我找不到这两种方法的比较。
任何见解都会有所帮助,谢谢!
1> Daniel Reard..:
重要的是要注意,数据加载器不仅是数据模型的接口。尽管数据加载器被吹捧为“基于各种远程数据源的简化且一致的API”,但与GraphQL结合使用时,它们的主要优势在于能够在单个请求的上下文中实现缓存和批处理。此类功能在处理潜在冗余数据的API中很重要(请考虑一下查询用户和每个用户的朋友-多次重访同一用户的可能性很大)。
另一方面,猫鼬的populate
方法实际上只是聚合多个MongoDB请求的一种方式。从这个意义上讲,比较两者就像比较苹果和橘子。
可以按照populate
问题中的说明进行更公平的比较,而不是按照以下方式添加解析器activities
:
activities: (task, _, context) => Activity.find().where('id').in(task.activities)
无论哪种方式,问题都取决于您是否将所有数据加载到父解析器中,还是让更深层次的解析器完成一些工作。因为仅针对请求中包含的字段调用解析器,所以这两种方法之间的性能可能会受到重大影响。
如果activities
请求该字段,则这两种方法将使服务器和数据库之间的往返次数相同-性能差异可能很小。但是,您的请求可能根本不包含该activities
字段。在这种情况下,activities
将永远不会调用解析器,并且我们可以通过创建一个单独的activities
解析器并在那里进行工作来保存一个或多个数据库请求。
在相关说明中...
据我了解,使用类似的$lookup
方法在MongoDB中聚合查询通常比仅使用性能要差populate
一些(关于此点的一些对话可以在此处找到)。但是,在关系数据库的上下文中,在考虑上述方法时还需要考虑一些其他因素。那是因为您可以使用联接完成在父解析器中的初始访存,这通常比发出单独的数据库请求要快得多。这意味着要以使“非活动性”字段查询变慢为代价,可以使其他查询变快得多。