使用graphql类型处理子筛选器上的关系数据的最佳方法

使用graphql类型处理子筛选器上的关系数据的最佳方法,graphql,typeorm,typegraphql,Graphql,Typeorm,Typegraphql,我对graphql/typeorm之间的关系数据查询有疑问。 最好的解释方法是举个例子:) 为了回答我的问题,我使用了prisma API,例如() 此API是StarWars GraphQL API的一个示例 如果我想获得所有电影和相关角色,我会这样查询: 案例A 在这种情况下,可以一次性调用关系数据库,同时检索电影和角色(sql select with join) 我的问题是,在这样的查询中添加过滤器时,如何保持sql性能 案例B 在本例中,我们似乎必须使用FieldResolver执行此操

我对graphql/typeorm之间的关系数据查询有疑问。 最好的解释方法是举个例子:)

为了回答我的问题,我使用了prisma API,例如() 此API是StarWars GraphQL API的一个示例

如果我想获得所有电影和相关角色,我会这样查询:

案例A 在这种情况下,可以一次性调用关系数据库,同时检索电影和角色(sql select with join) 我的问题是,在这样的查询中添加过滤器时,如何保持sql性能

案例B 在本例中,我们似乎必须使用FieldResolver执行此操作,并执行其他数据库调用以检索子级

要澄清,请参见以下示例:

案例A(简单实施) 对于typescript和typeorm中的nodejs后端,我们可以这样做: 实体:

解析程序:

    @Resolver(of => Film)
    export class FilmResolvers { 

      constructor(private readonly filmService: FilmService) {}

      @Query(returns => [Film])  
      async allFilms(@Args() args: QueryAllFilmDTO): Promise<Film[]> {    
        return this.filmService.findAll(args);
      }
    }

 @Resolver(of => Film)
 export class FilmResolvers {

  constructor(
    private readonly filmService: FilmService,    
    @InjectRepository(Person) private readonly personRepository: Repository<Person>,
    ) {}

  @ResolveProperty(type => [Person])  
  async characters(@Parent() film: Film, @Args() args: PersonQueryAllDTO) {

    // Low Performance in this case 
    const persons = await this.personRepository
      .createQueryBuilder('person')
      .leftJoin('person.films', 'film','film.id = :films_param',{films_param: [film.id]})      
      .getMany();

    return persons;
  }

  @Query(returns => [Film])  
  async allFilms(@Args() args: QueryAllFilmDTO): Promise<Film[]> {
    this.detectRelation(info.operation.selectionSet);        
    return this.filmService.findAll(args);
  }
}
@Resolver(of=>胶片)
导出类解析程序{
构造器(私有只读电影服务:电影服务){}
@查询(返回=>[Film])
异步allFilms(@Args()Args:QueryAllFilmTo):承诺{
返回此.filmService.findAll(args);
}
}
案例B(扩展实施)

解析程序:

    @Resolver(of => Film)
    export class FilmResolvers { 

      constructor(private readonly filmService: FilmService) {}

      @Query(returns => [Film])  
      async allFilms(@Args() args: QueryAllFilmDTO): Promise<Film[]> {    
        return this.filmService.findAll(args);
      }
    }

 @Resolver(of => Film)
 export class FilmResolvers {

  constructor(
    private readonly filmService: FilmService,    
    @InjectRepository(Person) private readonly personRepository: Repository<Person>,
    ) {}

  @ResolveProperty(type => [Person])  
  async characters(@Parent() film: Film, @Args() args: PersonQueryAllDTO) {

    // Low Performance in this case 
    const persons = await this.personRepository
      .createQueryBuilder('person')
      .leftJoin('person.films', 'film','film.id = :films_param',{films_param: [film.id]})      
      .getMany();

    return persons;
  }

  @Query(returns => [Film])  
  async allFilms(@Args() args: QueryAllFilmDTO): Promise<Film[]> {
    this.detectRelation(info.operation.selectionSet);        
    return this.filmService.findAll(args);
  }
}
@Resolver(of=>胶片)
导出类解析程序{
建造师(
私人只读电影服务:电影服务,
@InjectRepository(Person)私有只读personRepository:Repository,
) {}
@ResolveProperty(类型=>[Person])
异步字符(@Parent()film:film,@Args()Args:PersonQueryAllTo){
//在这种情况下,性能较低
const persons=wait this.personRepository
.createQueryBuilder(“人员”)
.leftJoin('person.films','film','film.id=:films\u param',{films\u param:[film.id]})
.getMany();
返回人员;
}
@查询(返回=>[Film])
异步所有电影(@Args()Args:queryalFilmDTO):承诺{
此.detectRelation(信息.操作.选择集);
返回此.filmService.findAll(args);
}
}
这里的问题是我们手动连接(两个数据库调用) 我正在考虑其他解决方案,但我需要您的审核:

案例B(其他扩展实施) 我的目标是检索ExtendendGraphQL请求信息,检测查询中的关系,并使用join构造sql查询

 @Resolver(of => Film)
 export class FilmResolvers { 

  constructor(
    private readonly filmService: FilmService,  
    @InjectRepository(Person) private readonly personRepository: Repository<Person>,
    ) {}


    @Query(returns => [Film])  
  async allFilms(@Args() args: QueryAllFilmDTO, @Info() info: GraphQLResolveInfo): Promise<Film[]> {

    const relations: string[] = [];
    this.getRelations(info.operation.selectionSet, (relation) =>{
      relations.push(relation);
    });

    return this.filmService.findAll(args, relations);
  }




  private getRelations(selectionSetNode: SelectionSetNode, callback: relationCallback, level=0){      
      selectionSetNode.selections.forEach( (subSelection) => {                
        if(subSelection.kind === 'Field'){
          const fieldNode = subSelection as FieldNode;          
          if(fieldNode.selectionSet){
            if(level)              
              callback(fieldNode.name.value);            
            this.getRelations(fieldNode.selectionSet, callback, ++level);        
          }
        }        
      });
  }
}
@Resolver(of=>胶片)
导出类解析程序{
建造师(
私人只读电影服务:电影服务,
@InjectRepository(Person)私有只读personRepository:Repository,
) {}
@查询(返回=>[Film])
异步所有电影(@Args()Args:queryalfilmdto,@Info()Info:graphqlsolveinfo):承诺{
常量关系:字符串[]=[];
this.getRelations(info.operation.selectionSet,(relations)=>{
关系。推(关系);
});
返回此.filmService.findAll(args,relations);
}
私有getRelations(selectionSetNode:selectionSetNode,回调:relationCallback,级别=0){
selectionSetNode.selections.forEach((子选择)=>{
if(subSelection.kind=='Field'){
const fieldNode=作为fieldNode的子选择;
if(fieldNode.selectionSet){
如果(级别)
回调(fieldNode.name.value);
this.getRelations(fieldNode.selectionSet,回调,++level);
}
}        
});
}
}
这是一个好的选择吗?或者有没有其他方法来优化数据库调用

 @Resolver(of => Film)
 export class FilmResolvers { 

  constructor(
    private readonly filmService: FilmService,  
    @InjectRepository(Person) private readonly personRepository: Repository<Person>,
    ) {}


    @Query(returns => [Film])  
  async allFilms(@Args() args: QueryAllFilmDTO, @Info() info: GraphQLResolveInfo): Promise<Film[]> {

    const relations: string[] = [];
    this.getRelations(info.operation.selectionSet, (relation) =>{
      relations.push(relation);
    });

    return this.filmService.findAll(args, relations);
  }




  private getRelations(selectionSetNode: SelectionSetNode, callback: relationCallback, level=0){      
      selectionSetNode.selections.forEach( (subSelection) => {                
        if(subSelection.kind === 'Field'){
          const fieldNode = subSelection as FieldNode;          
          if(fieldNode.selectionSet){
            if(level)              
              callback(fieldNode.name.value);            
            this.getRelations(fieldNode.selectionSet, callback, ++level);        
          }
        }        
      });
  }
}