Golang gqlgen,通过Dataloading在单个DB查询中获取单独的字段。

huangapple go评论96阅读模式
英文:

Golang gqlgen, fetching separate fields in a single DB query via Dataloading

问题

我正在尝试确定是否可能将具有自己的解析器的多个字段合并到单个数据库查询中,因为它们是从同一位置获取的。

例如,模式如下:

type ExampleResponse {
  A: Int!
  B: Int!
  C: Int!
}

gqlgen.yml配置文件如下:

models:
  ExampleResponse:
    fields:
      A:
        resolver: true
      B:
        resolver: true
      C:
        resolver: true

现在,如果在同一时间请求A和B,我希望从同一个数据库调用中获取它们。

我有一个基于键返回这些值的API:

exampleRes, err := resolver.service.GetExample(ctx, GetExampleRequest{
	Keys: []ExampleKey{
		AKey,
		BKey,
	},
})

这种方式是否可行,还是我需要重新考虑我的方法?

生成的解析器如下:

func (r *exampleResponseResolver) A(ctx context.Context, obj *model.ExampleResponse) (int, error) {
	panic(fmt.Errorf("not implemented"))
}

func (r *exampleResponseResolver) B(ctx context.Context, obj *model.ExampleResponse) (int, error) {
	panic(fmt.Errorf("not implemented"))
}

func (r *exampleResponseResolver) C(ctx context.Context, obj *model.ExampleResponse) (int, error) {
	panic(fmt.Errorf("not implemented"))
}
英文:

I am trying to see if its possible to take several fields that have their own resolver and somehow get them in a single DB query since they are fetched from the same place.

Eg. the schema

type ExampleResposne {
  A: Int!
  B: Int!
  C: Int!
}

The gqlgen.yml

models:
  ExampleResponse:
    fields:
      A:
        resolver: true
      B:
        resolver: true
      C:
        resolver: true

And now somehow I'd like to fetch A and B from a same DB call if they are requested at the same time

I have an API that returns these based on the keys

	exampleRes, err := resolver.service.GetExample(ctx, GetExampleRequest{
		Keys: []ExampleKey{
			AKey,
			BKey,
		},
	})

Is something like this possible or should I rethink my approach?

The generated resolvers

func (r *exampleResponseResolver) A(ctx context.Context, obj *model.ExampleResponse) (int, error) {	panic(fmt.Errorf("not implemented"))
}

func (r *exampleResponseResolver) B(ctx context.Context, obj *model.ExampleResponse) (int, error) {	panic(fmt.Errorf("not implemented"))
}

func (r *exampleResponseResolver) C(ctx context.Context, obj *model.ExampleResponse) (int, error) {	panic(fmt.Errorf("not implemented"))
}

答案1

得分: 1

看起来你可能对一些主题有些混淆:

数据加载(Dataloading)

数据加载的概念是将多个数据请求批量处理在一个解析器的函数/方法调用下。这应该在解析类型的级别考虑,而不是在该类型的各个字段的级别考虑。

一个例子(来自https://gqlgen.com/reference/dataloaders/)是在一个数据库请求中解析多个Users

GraphQL字段解析器(Field Resolvers)

根据你的gqlgen.yml配置,你已经为字段指定了单独的解析器,例如:

models:
  ExampleResponse:
    fields:
      A:
        resolver: true
      ...

字段解析器的概念是解析类型的各个字段,而不是将整个类型作为一个整体解析,实际上与数据加载的效果相反。这在我们尝试解析带有参数的字段或者代码拆分解析器逻辑时非常有用。

需要注意的是,如果使用不当,字段解析器经常会导致N+1问题

解决方案

你可能没有看到类型ExampleResponse的解析器,是因为你需要将查询入口点添加到Query类型下。

schema.graphql:

type Query {
    getExample: ExampleResponse
}

然后运行:go run github.com/99designs/gqlgen generate

你应该会看到:

func (r *queryResolver) GetExample(ctx context.Context) (*model.ExampleResponse, error) { 
    panic(fmt.Errorf("not implemented"))
}

详细信息请参阅https://graphql.org/learn/schema/#the-query-and-mutation-types。

英文:

It seems you may have some topics confused:


Dataloading

The concept of dataloading is to batch multiple requests for data under one resolver's function / method call. This should be considered at the level of the resolving type and not at the level of individual fields of that type.

An example of this (taken from https://gqlgen.com/reference/dataloaders/) would be to resolve for multiple Users under one database request.


Graphql Field Resolvers

With your gqlgen.yml configuration, you have specified individual resolvers for fields with:

models:
  ExampleResponse:
    fields:
      A:
        resolver: true
      ...

The concept of field resolvers aim to resolve individual fields of a type rather than to resolve the type as a whole, essentially having the opposite effect to what dataloading has. This is useful when we are trying to resolve argumented fields or code splitting resolver logic.

To note, field resolvers can often cause N+1 problems when not used effectively.


The Solution

You might not be seeing a resolver for your type ExampleResponse because you need to append your queries entry-point under the Query type.

schema.graphql:

type Query {
    getExample: ExampleResposne
}

Then run: go run github.com/99designs/gqlgen generate

You should see:

func (r *queryResolver) GetExample(ctx context.Context) (*model.ExampleResponse, error) { 
    panic(fmt.Errorf("not implemented"))
}

See https://graphql.org/learn/schema/#the-query-and-mutation-types for details.

huangapple
  • 本文由 发表于 2022年8月30日 14:15:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/73537888.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定