Hi all,
I face some performance issues linked to a costly nested resolver.
I have a GQL endpoint that roughly looks as follows
type Query {
foos(): [Foo!]!
}
type Foo {
id: ID!
fieldA: string
fieldB(input: Object): [Int!]! # Uses info from Foo + input to run an SQL query
}
// simplified resolver
const FooResolvers: Resolvers = {
Query: {
foos: async (
_parent,
args: QueryFooArgs,
context: Context,
info: GraphQLResolveInfo
): Promise<GQLFoo[]> => {
return sql.fetchFoos(); // fieldB === undefined
}
},
Foo: fieldB: async (
parent: GQLFoo,
args: FooFieldBArgs,
context: Context
): Promise<FieldB> => {
return sql.groupByAndSum(args.input, parent.id);
},
I have a nested resolved for fieldB which works fine.
- I fetch all
Foos in thefoos()query resolver, and then - in the
Foo::fieldBnested resolver, I use theFoodetails +fieldB’s input to producefieldB. However, it’s a relatively complex aggregation that requires a read on my database.
Given that foos() returns an array of Foo, which can grow relatively large, I would rather not do N individual requests to my DB.
For something like fieldA, even if it needed some computation, I know that I can access the field list in the top query resolver by using info.fieldNodes[0]?.selectionSet. However, it seems slightly more complicated, and way less reliable for fieldB, since it has argument in the form of an object.
My questions are:
- This generally seems like an anti-pattern. Is there a better way to batch my nested resolvers?
- Is there a proper way to access my nested resolver’s arguments from the top query?
Thanks in advance!