我对graphql / typeorm之间的关系数据查询有疑问。 最好的解释方法是举一个例子:)
出于我的问题,我使用了例如Arizona(https://www.graphqlbin.com/v2/6RQ6TM) 该API是StarWars GraphQL API的示例
如果我想获得所有电影和相关角色,我会这样查询:
{
allFilms{
title
characters{
name
}
}
}
在这种情况下,可以一次完成关系数据库调用,一起检索影片和角色(通过联接选择sql) 我的问题是在这样的查询中添加过滤器时如何保持sql性能
{
allFilms{
title
characters(filter: {name_contains: "PO"}){
name
}
}
}
在这种情况下,似乎我们必须使用FieldResolver进行此操作,并执行其他数据库调用来检索子项
为澄清起见,请参见以下示例:
案例A(简单实施) 如果是typescript和typeorm ORM中的nodejs后端,我们可以这样: 实体:
@Entity()
@ObjectType()
export class Film {
@PrimaryColumn()
@Field(type => ID, { description: 'The id of the object.'})
id: string;
@Column()
@Field({ description: 'The title of this film'})
title: string;
.....
@ManyToMany(type => Person, person => person.films )
@JoinTable({ name: 'film_person' })
@Field(type => [Person], { nullable: true })
characters?: Person[];
}
解析器:
@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);
}
}
案例B(扩展实施)
解析器:
@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);
}
}
这里的问题是我们进行手动联接(两个数据库调用) 我正在考虑其他解决方案,但需要您的审查:
案例B(其他扩展实施) 我的目标检索extendend graphql请求信息,检测查询中的关系并使用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);
}
}
});
}
}
这是一个好选择吗?还是有其他方法可以优化数据库调用?