如何在Apollo GraphQL服务器的孙解析器中访问祖父节点数据?
在GraphQL孙解析器中访问祖父同级字段的数据
要在grandchild1的解析器中获取同级根字段field1的数据,主要有两种可靠方案,可根据业务场景选择:
方案一:通过上下文(Context)传递数据
上下文是GraphQL解析器间共享数据的核心载体,你可以把field1的数据存入上下文,供所有子解析器访问。
注意事项
GraphQL会并行处理同级根字段(比如field1和field2),如果直接在field1的解析器中把数据存入上下文,可能出现grandchild1解析时field1还未执行完成的情况。因此建议在请求初始化阶段预取field1的数据,或者确保数据获取逻辑是异步安全的。
示例代码(Apollo Server)
# 类型定义 type Query { field1: String field2: Field2Type } type Field2Type { child1: Child1Type } type Child1Type { grandchild1: String }
// 解析器实现 const resolvers = { Query: { async field1(_, __, context) { const field1Data = await context.dataSources.api.getField1(); // 将数据存入上下文的共享对象 context.shared.field1 = field1Data; return field1Data; }, field2() { return {}; // 返回field2的基础结构,实际根据业务调整 }, }, Field2Type: { child1() { return {}; }, }, Child1Type: { async grandchild1(_, __, context) { // 从上下文获取field1数据,若并行未完成则重新请求(结合缓存避免重复) const field1Data = context.shared.field1 || await context.dataSources.api.getField1(); return `基于field1数据生成的结果:${field1Data}`; }, }, }; // 配置上下文 const server = new ApolloServer({ typeDefs, resolvers, context: () => ({ shared: {}, // 用于存储共享数据的对象 dataSources: { api: new APIDataSource(), // 自定义数据源,封装数据请求逻辑 }, }), });
方案二:使用DataLoader避免重复查询
如果field1的数据来自外部接口或数据库,可以用DataLoader缓存查询结果。即使grandchild1的解析器再次请求field1的数据,DataLoader会自动返回缓存值,不会重复发起请求。
示例代码
// 初始化DataLoader const { DataLoader } = require('dataloader'); function createField1Loader(api) { return new DataLoader(async () => { // 假设field1是单值数据,批量查询逻辑可根据业务调整 const data = await api.getField1(); return [data]; }); } // 配置上下文时传入DataLoader const server = new ApolloServer({ typeDefs, resolvers, context: () => ({ dataSources: { api: new APIDataSource(), field1Loader: createField1Loader(new APIDataSource()), }, }), }); // 解析器中使用DataLoader const resolvers = { Query: { async field1(_, __, context) { // 通过DataLoader获取数据,自动缓存 return context.dataSources.field1Loader.load('unique-key'); }, field2() { return {}; }, }, Child1Type: { async grandchild1(_, __, context) { // 再次调用DataLoader,直接获取缓存值 const field1Data = await context.dataSources.field1Loader.load('unique-key'); return `处理结果:${field1Data}`; }, }, };
不推荐的方案
- 直接在
grandchild1解析器中重新查询field1:会导致重复请求,降低性能。 - 通过遍历AST查询结构获取数据:实现复杂且不稳定,因为运行时数据还未完全生成。
内容的提问来源于stack exchange,提问作者Vinit Khandelwal
相关产品推荐
相关产品推荐

