使用 Apollo Graphql Server 解析关系文档
Resolving relational document using Apollo Graphql Server
我在 Apollo graphql 中实施了 Post 评论模型,我想知道哪个实施是正确的?
type Post {
id: ID!
title: String
image: File
imagePublicId: String
comments: [Comment] # we have type for Comment in another schema file
createdAt: String
updatedAt: String
}
extend type Query {
# Gets post by id
getPosts(authUserId: ID!, skip: Int, limit: Int): Post
}
我有一个解析器,它解析 Post 类型,并借助 mongoose 的填充函数解析注释,如下所示:
const Query = {
getPosts: async (root, { authUserId, skip, limit }, { Post }) => {
const allPosts = await Post.find(query)
.populate({
path: 'comments',
options: { sort: { createdAt: 'desc' } },
populate: { path: 'author' },
})
.skip(skip)
.limit(limit)
.sort({ createdAt: 'desc' });
return allPosts
}
}
在解析器中实现 getPosts 查询的第二种方法可能的方法是不使用 mongoose 的填充函数,并通过为它:
const Query = {
getPosts: async (root, { authUserId, skip, limit }, { Post }) => {
const allPosts = await Post.find(query)
.skip(skip)
.limit(limit)
.sort({ createdAt: 'desc' });
return allPosts
}
Post: {
comments: (root, args, ctx, info) => {
return Comment.find({post: root._id}).exec()
}
}
}
视情况而定。
解析器只有在其字段被请求时才会被触发。因此,如果 getPosts
解析器获取没有评论的 post,而 comments
解析器获取每个 post 的评论,评论将 仅 [=如果 comments
字段包含在请求中,则获取 35=]。这可以通过防止后端过度获取来提高此类请求的性能。
另一方面,通过单独查询每个 post 的评论,您将大大增加对数据库的请求数量 (the n+1 problem)。我们可以通过在一个查询中获取所有 post 和所有评论来避免这个问题,但是,同样,我们可能根本不需要评论。
解决这个难题有两种选择:
获取 comments
解析器中的注释,但使用 dataloader 对数据库请求进行批处理。这样你就可以发出 2 个数据库请求,而不是 n + 1 个。
解析作为第四个参数传递给解析器的 GraphQLResolveInfo 对象,以确定是否请求了 comments
字段。这样,您可以有条件地添加 populate
调用,仅当实际请求了 comments
字段时。
我在 Apollo graphql 中实施了 Post 评论模型,我想知道哪个实施是正确的?
type Post {
id: ID!
title: String
image: File
imagePublicId: String
comments: [Comment] # we have type for Comment in another schema file
createdAt: String
updatedAt: String
}
extend type Query {
# Gets post by id
getPosts(authUserId: ID!, skip: Int, limit: Int): Post
}
我有一个解析器,它解析 Post 类型,并借助 mongoose 的填充函数解析注释,如下所示:
const Query = {
getPosts: async (root, { authUserId, skip, limit }, { Post }) => {
const allPosts = await Post.find(query)
.populate({
path: 'comments',
options: { sort: { createdAt: 'desc' } },
populate: { path: 'author' },
})
.skip(skip)
.limit(limit)
.sort({ createdAt: 'desc' });
return allPosts
}
}
在解析器中实现 getPosts 查询的第二种方法可能的方法是不使用 mongoose 的填充函数,并通过为它:
const Query = {
getPosts: async (root, { authUserId, skip, limit }, { Post }) => {
const allPosts = await Post.find(query)
.skip(skip)
.limit(limit)
.sort({ createdAt: 'desc' });
return allPosts
}
Post: {
comments: (root, args, ctx, info) => {
return Comment.find({post: root._id}).exec()
}
}
}
视情况而定。
解析器只有在其字段被请求时才会被触发。因此,如果 getPosts
解析器获取没有评论的 post,而 comments
解析器获取每个 post 的评论,评论将 仅 [=如果 comments
字段包含在请求中,则获取 35=]。这可以通过防止后端过度获取来提高此类请求的性能。
另一方面,通过单独查询每个 post 的评论,您将大大增加对数据库的请求数量 (the n+1 problem)。我们可以通过在一个查询中获取所有 post 和所有评论来避免这个问题,但是,同样,我们可能根本不需要评论。
解决这个难题有两种选择:
获取
comments
解析器中的注释,但使用 dataloader 对数据库请求进行批处理。这样你就可以发出 2 个数据库请求,而不是 n + 1 个。解析作为第四个参数传递给解析器的 GraphQLResolveInfo 对象,以确定是否请求了
comments
字段。这样,您可以有条件地添加populate
调用,仅当实际请求了comments
字段时。