[英]How can I use the fields in a GraphQL query to perform nested reads with Prisma?
我正在使用 Prisma 来实现 GraphQL 接口,以公开存储在 PostgreSQL 数据库中的一些数据。 我的代码受到GraphQL Tools (SDL-first) 示例的启发。 这个逻辑虽然效率很低,但我想改进它。
这是显示问题并寻求解决方案的最少代码段。 我的真实代码当然更复杂。
type Query {
allUsers: [User!]!
}
type User {
name: String!
posts: [Post!]!
}
type Post {
text: String!
author: User!
}
const resolvers = {
Query: {
allUsers: ()=>prisma.users.findMany()
},
User: {
posts: (user)=>prisma.posts.findMany({where:{author:user.id}})
}
};
此代码有效,但效率低下。 假设您正在运行查询{allUsers{posts{text}}}
:
我的代码对 PostgreSQL 运行 N+1 个查询来获取整个结果:一个来获取用户列表,然后是另一个 N:每个用户一个。 使用 JOIN 的单个查询就足够了。
我的代码从它查询的每个表中选择每一列,即使我只需要user.id
而不需要user.name
或其他任何东西。
我知道 Prisma 支持嵌套搜索( include
和select
选项) ,这可以解决这两个问题。 但是我不知道如何使用 GraphQL 查询配置选项对象。
如何从 GraphQL 查询中提取请求的字段列表? 以及如何使用这些创建选项对象以使用 Prisma 执行最佳嵌套搜索?
这个包可以帮助你解析请求信息: https ://www.npmjs.com/package/graphql-parse-resolve-info
然后,您需要将其转换为可以在 ORM 中使用的可用参数。
这是 NestJS 的示例:
import {createParamDecorator, ExecutionContext} from '@nestjs/common';
import {GqlExecutionContext} from '@nestjs/graphql';
import {GraphQLResolveInfo} from 'graphql';
import {parseResolveInfo, ResolveTree} from 'graphql-parse-resolve-info';
export type PrismaSelect = {
select: {
[key: string]: true | PrismaSelect;
};
};
export const Relations = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const info = GqlExecutionContext.create(ctx).getInfo<GraphQLResolveInfo>();
const ast = parseResolveInfo(info);
return astToPrisma(Object.values((ast as ResolveTree).fieldsByTypeName)[0]);
},
);
export const astToPrisma = (ast: {
[str: string]: ResolveTree;
}): PrismaSelect => {
return {
select: Object.fromEntries(
Object.values(ast).map(field => [
field.name,
Object.keys(field.fieldsByTypeName).length === 0
? true
: astToPrisma(Object.values(field.fieldsByTypeName)[0]),
]),
),
};
};
然后你做:
import {Parent, Query, ResolveField, Resolver} from '@nestjs/graphql';
import {PrismaService} from '../services/prisma.service';
import {User} from '../entities/user.entity';
import {Relations} from 'src/decorators/relations.decorator';
import {Prisma} from '@prisma/client';
@Resolver(() => User)
export class UserResolver {
constructor(public prisma: PrismaService) {}
@Query(() => [User])
async usersWithRelationsResolver(
@Relations() relations: {select: Prisma.UserSelect},
): Promise<Partial<User>[]> {
return this.prisma.user.findMany({
...relations,
});
}
或者,如果你想解决 N+1 问题,你可以使用 Prisma 内置的findUnique
方法。 请参阅https://www.prisma.io/docs/guides/performance-and-optimization/query-optimization-performance#solving-the-n1-problem
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.