[英]How can I use the fields in a GraphQL query to perform nested reads with Prisma?
I'm using Prisma to implement a GraphQL interface to expose some data stored in a PostgreSQL database.我正在使用 Prisma 来实现 GraphQL 接口,以公开存储在 PostgreSQL 数据库中的一些数据。 My code is inspired by the GraphQL Tools (SDL-first) example .
我的代码受到GraphQL Tools (SDL-first) 示例的启发。 This logic is pretty inefficient though and I'd like to improve it.
这个逻辑虽然效率很低,但我想改进它。
Here is a minimal piece of code to show the problem and ask for a solution.这是显示问题并寻求解决方案的最少代码段。 My real code is of course more complicated.
我的真实代码当然更复杂。
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}})
}
};
This code works but it's inefficient.此代码有效,但效率低下。 Imagine you're running the query
{allUsers{posts{text}}}
:假设您正在运行查询
{allUsers{posts{text}}}
:
My code runs N+1 queries against PostgreSQL to fetch the whole result: one to fetch the list of the users, then other N: one for each user.我的代码对 PostgreSQL 运行 N+1 个查询来获取整个结果:一个来获取用户列表,然后是另一个 N:每个用户一个。 A single query, using a JOIN, should be enough.
使用 JOIN 的单个查询就足够了。
My code selects every column from every table it queries, even though I only need user.id
and don't need user.name
or anything else.我的代码从它查询的每个表中选择每一列,即使我只需要
user.id
而不需要user.name
或其他任何东西。
I know that Prisma supports nested searches ( include
and select
options) which could fix both problems.我知道 Prisma 支持嵌套搜索(
include
和select
选项) ,这可以解决这两个问题。 However I don't know how to configure the options object using the GraphQL query.但是我不知道如何使用 GraphQL 查询配置选项对象。
How can I extract from the GraphQL query the list of fields that are requested?如何从 GraphQL 查询中提取请求的字段列表? And how can I use these to create to options object to perform an optimal nested-search with Prisma?
以及如何使用这些创建选项对象以使用 Prisma 执行最佳嵌套搜索?
This package can help you parse the request info: https://www.npmjs.com/package/graphql-parse-resolve-info这个包可以帮助你解析请求信息: https ://www.npmjs.com/package/graphql-parse-resolve-info
Then you need to transform it to a usable parameter that you can use in your ORM.然后,您需要将其转换为可以在 ORM 中使用的可用参数。
Here is an example with NestJS:这是 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]),
]),
),
};
};
Then you do:然后你做:
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,
});
}
Alternatively, if you want to solve the N+1 problem you can use Prisma built-in findUnique
method.或者,如果你想解决 N+1 问题,你可以使用 Prisma 内置的
findUnique
方法。 See https://www.prisma.io/docs/guides/performance-and-optimization/query-optimization-performance#solving-the-n1-problem请参阅https://www.prisma.io/docs/guides/performance-and-optimization/query-optimization-performance#solving-the-n1-problem
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.