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
Foo
s in thefoos()
query resolver, and then - in the
Foo::fieldB
nested resolver, I use theFoo
details +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!