Prisma:查询子关系的最有效方式
Prisma: Most performant way to query for sub relations
我想查询 post 和每个 post 我不只是当前用户的点赞。
我有 2 个解决方案,并且都有效。但是哪个更好呢?或者有更好的解决方案吗?
- 前端:React + ApolloClient
- 后端:Primsa2 + Graphql Nexus
Prisma 模式:
model Post {
id String @id @default(cuid())
likes Like[]
}
model Like {
id String @id @default(cuid())
post Post? @relation(fields: [postId], references: [id])
postId String?
user User @relation(fields: [userId], references: [id])
userId String
}
model User {
id String @id @default(cuid())
likes Like[]
}
两种解决方案的查询字段相同:
export const posts = queryField('posts', {
type: 'Post',
list: true,
resolve: async (_parent, args: any, { prisma, request }, info) => {
opArgs={
//unimportant
}
return prisma.post.findMany(opArgs)
},
})
- 解决方法:我直接在apollo client的查询里用where条件请求like之类的
前端:ApolloClient
const POSTS_USER = gql`
query posts(
$currentUserId: String
) {
posts {
id
likes(where: { user: { id: { equals: $currentUserId } } }) { // where condition!
id
}
}
}
`;
const POSTS_NO_USER = gql`
query posts(
$currentUserId: String
) {
posts {
id
}
}
`;
const { data, loading } = useQuery(user? POSTS_USER: POSTS_NO_USER, {
variables: {
currentUserId: user ? user.id : "",
},
});
后端 Nexus 对象:
const Post = objectType({
name: 'Post',
definition(t) {
t.model.id()
t.model.likes({
filtering: {
user: true,
},
})
},
})
- 解决方案:我为objectType Post 设置了likes 的字段条件。
前端:ApolloClient
const POSTS = gql`
query posts {
posts {
id
likes { // NO where condition!
id
}
}
}
`;
const { data, loading } = useQuery(POSTS);
使用 Nexus 的后端:
const Post = objectType({
name: 'Post',
definition(t) {
t.model.id()
t.model.likes()
t.list.field('likes', {
type: 'Like',
list: true,
resolve: (parent, args, { prisma, request }) => {
const user = getUser(request, false)
if (!user) {
return []
} else {
return prisma.like.findMany({
where: {
postId: parent.id,
userId: user.id,
},
})
}
},
})
},
})
第一种方法更好,为什么?
当您进行第一个查询时,prisma 将在 1 个数据库查询中执行您的查询。
当您进行第二个查询时,您将有数据库查询,因为您有帖子编号
使用我的 PrismaSelect 插件 Prisma Select 的最佳方式是将 info: GraphQLResolveInfo
对象中的一般 graphql 参数(parent、args、context、info)带到 select 对象被 prisma client
接受。该方法允许更好的性能,因为您将只使用一个解析器来检索您的所有请求。通过这样做,它也消除了 N + 1
问题。
但您还需要停止使用 nexus-plugin-prisma 并使用我的 pal.js CLI 来 auto-generate 您的 CRUD
我想查询 post 和每个 post 我不只是当前用户的点赞。
我有 2 个解决方案,并且都有效。但是哪个更好呢?或者有更好的解决方案吗?
- 前端:React + ApolloClient
- 后端:Primsa2 + Graphql Nexus
Prisma 模式:
model Post {
id String @id @default(cuid())
likes Like[]
}
model Like {
id String @id @default(cuid())
post Post? @relation(fields: [postId], references: [id])
postId String?
user User @relation(fields: [userId], references: [id])
userId String
}
model User {
id String @id @default(cuid())
likes Like[]
}
两种解决方案的查询字段相同:
export const posts = queryField('posts', {
type: 'Post',
list: true,
resolve: async (_parent, args: any, { prisma, request }, info) => {
opArgs={
//unimportant
}
return prisma.post.findMany(opArgs)
},
})
- 解决方法:我直接在apollo client的查询里用where条件请求like之类的
前端:ApolloClient
const POSTS_USER = gql`
query posts(
$currentUserId: String
) {
posts {
id
likes(where: { user: { id: { equals: $currentUserId } } }) { // where condition!
id
}
}
}
`;
const POSTS_NO_USER = gql`
query posts(
$currentUserId: String
) {
posts {
id
}
}
`;
const { data, loading } = useQuery(user? POSTS_USER: POSTS_NO_USER, {
variables: {
currentUserId: user ? user.id : "",
},
});
后端 Nexus 对象:
const Post = objectType({
name: 'Post',
definition(t) {
t.model.id()
t.model.likes({
filtering: {
user: true,
},
})
},
})
- 解决方案:我为objectType Post 设置了likes 的字段条件。
前端:ApolloClient
const POSTS = gql`
query posts {
posts {
id
likes { // NO where condition!
id
}
}
}
`;
const { data, loading } = useQuery(POSTS);
使用 Nexus 的后端:
const Post = objectType({
name: 'Post',
definition(t) {
t.model.id()
t.model.likes()
t.list.field('likes', {
type: 'Like',
list: true,
resolve: (parent, args, { prisma, request }) => {
const user = getUser(request, false)
if (!user) {
return []
} else {
return prisma.like.findMany({
where: {
postId: parent.id,
userId: user.id,
},
})
}
},
})
},
})
第一种方法更好,为什么?
当您进行第一个查询时,prisma 将在 1 个数据库查询中执行您的查询。 当您进行第二个查询时,您将有数据库查询,因为您有帖子编号
使用我的 PrismaSelect 插件 Prisma Select 的最佳方式是将 info: GraphQLResolveInfo
对象中的一般 graphql 参数(parent、args、context、info)带到 select 对象被 prisma client
接受。该方法允许更好的性能,因为您将只使用一个解析器来检索您的所有请求。通过这样做,它也消除了 N + 1
问题。
但您还需要停止使用 nexus-plugin-prisma 并使用我的 pal.js CLI 来 auto-generate 您的 CRUD