使用Relay设置分页非常容易,但是有一个小细节我不清楚。
我的代码中的两个相关部分都标有注释,其他代码用于附加上下文。
const postType = new GraphQLObjectType({
name: 'Post',
fields: () => ({
id: globalIdField('Post'),
title: {
type: GraphQLString
},
}),
interfaces: [nodeInterface],
})
const userType = new GraphQLObjectType({
name: 'User',
fields: () => ({
id: globalIdField('User'),
email: {
type: GraphQLString
},
posts: {
type: postConnection,
args: connectionArgs,
resolve: async (user, args) => {
// getUserPosts() is in next code block -> it gets the data from db
// I pass args (e.g "first", "after" etc) and user id (to get only user posts)
const posts = await getUserPosts(args, user._id)
return connectionFromArray(posts, args)
}
},
}),
interfaces: [nodeInterface],
})
const {connectionType: postConnection} =
connectionDefinitions({name: 'Post', nodeType: postType})
exports.getUserPosts = async (args, userId) => {
try {
// using MongoDB and Mongoose but question is relevant with every db
// .limit() -> how many posts to return
const posts = await Post.find({author: userId}).limit(args.first).exec()
return posts
} catch (err) {
return err
}
}
我混淆的原因:
first
参数并在db query中使用它来限制返回的结果,hasNextPage
总是 false
。这是有效的,但如果您使用hasNextPage
,它会中断hasPreviousPage
(last
)first
参数并且不在db查询中使用它来限制返回的结果,hasNextPage
正在按预期工作但它将返回全部我查询的项目(可能是数千)
这里的逻辑是什么?
我想到的一个解决方案是在+1
中添加first
到getUserPosts
值,它会检索一个多余的项目,而hasNextPage
可能会有效。但这感觉就像一个 hack 并且总是返回多余的项目 - 如果有很多connections
和请求,它会相对快速地增长。
我们是否应该像那样破解它?是否预期返回所有结果?
或者我是否误解了数据库与GrahpQL / Relay之间的整个关系?
如果我使用FB DataLoader和Redis怎么办?这会改变那种逻辑吗?
答案 0 :(得分:4)
我混淆的原因
graphql-relay-js库的效用函数connectionFromArray
不是解决各种分页需求的方法。我们需要根据我们首选的分页模型调整我们的方法。
connectionFromArray
函数从给定数组派生hasNextPage
和hasPrevisousPage
的值。所以,你在“我的困惑的原因”中观察和提到的是预期的行为。
至于是否加载所有数据的困惑,这取决于手头的问题。在以下几种情况下加载所有项目可能有意义:
两种常见的分页模型是编号页面和无限滚动。 GraphQL连接规范并不是关于分页模型的观点,而是允许它们。
对于带编号的页面,您可以在GraphQL类型中使用额外的字段totalPost
,该字段可用于显示UI上编号页面的链接。在后端,您可以使用skip
之类的功能来仅获取所需的项目。字段totalPost
和当前页码消除了对hasNextPage
或hasPreviousPage
的依赖。
对于无限滚动,您可以使用cursor
字段,该字段可用作查询中after
的值。在后端,您可以使用cursor
的值来检索下一个项目(first
的值)。请参阅Relay documention on GraphQL connection中使用光标的示例。有关GraphQL连接和游标的信息,请参阅this answer。请参阅this和this博文,这有助于您更好地理解cursor
的想法。
这里的逻辑是什么?
我们是否应该像那样破解它?
不,理想情况下,我们不会想要破解和遗忘它。这将在项目中留下技术债务,这可能会在长期内造成更多问题。您可以考虑实现自己的函数来返回连接对象。您将在graphql-relay-js中的array-connection实现中了解如何执行此操作。
预计返回所有结果吗?
再次,取决于问题。
如果我使用FB DataLoader和Redis怎么办?这会改变那种逻辑吗?
您可以使用facebook dataloader库来缓存和批处理您的查询。 Redis是缓存结果的另一种选择。如果使用dataloader加载(1)所有项目或将所有项目存储在Redis中,并且(2)项目是轻量级的,则可以轻松创建所有项目的数组(遵循KISS原则)。如果物品很重,那么创建阵列可能是一项昂贵的操作。