relayjs - 使用连接和分页时GraphQL与数据库之间的关系?

标签 relayjs graphql-js

使用 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 参数并在数据库查询中使用它来限制返回的结果,则 hasNextPagealways false.这很有效,但会破坏 hasNextPage(如果您使用 last,则为 hasPreviousPage)
  • 如果我不传递 first 参数,也不在数据库查询中使用它来限制返回的结果,hasNextPage 将按预期工作,但会返回 < strong>所有我查询的项目(可能有数千个)
    • 即使数据库位于同一台计算机上(大型应用程序并非如此),这看起来也非常非常低效且糟糕。请证明我是错的!
    • 据我所知,GraphQL 没有任何服务器端缓存,因此没有必要返回所有结果(即使返回,用户也不会浏览 100% 的内容)

这里的逻辑是什么?

我想到的一个解决方案是将+1添加到getUserPosts中的first值,它将检索一个多余的项目并hasNextPage 可能会起作用。但这感觉就像是黑客,并且总是返回多余的项目 - 如果有很多连接和请求,它会相对较快地增长。

我们会像这样破解它吗?是否期望返回所有结果?

或者我是否误解了数据库和 GrahpQL/Relay 之间的整个关系?


如果我使用 FB DataLoader 会怎么样?还有雷迪斯?这会改变这个逻辑吗?

最佳答案

Cause of my confusion

graphql-relay-js 库的实用函数 connectionFromArray 并不能解决所有类型的分页需求。我们需要根据我们首选的分页模型调整我们的方法。

connectionFromArray 函数从给定数组派生 hasNextPagehasPrevisousPage 的值。因此,您在“我感到困惑的原因”中观察到并提到的行为是预期的行为。

至于您是否困惑是否加载所有数据,这取决于您当前的问题。加载所有项目在多种情况下可能有意义,例如:

  • 项目数量很少,您可以负担得起存储这些项目所需的内存。
  • 这些项目会被频繁请求,您需要缓存它们以便更快地访问。

两种常见的分页模型是编号页面和无限滚动。 GraphQL 连接规范对分页模型没有固执己见,并且允许两者。

对于编号页面,您可以在 GraphQL 类型中使用额外字段 totalPost,该字段可用于在 UI 上显示指向编号页面的链接。在后端,您可以使用 skip 等功能来仅获取所需的项目。字段totalPost和当前页码消除了对hasNextPagehasPreviousPage的依赖。

对于无限滚动,您可以使用 cursor 字段,该字段可用作查询中 after 的值。在后端,您可以使用 cursor 的值来检索下一个项目(first 的值)。请参阅 Relay documention on GraphQL connection 中使用光标的示例。 。请参阅this answer关于 GraphQL 连接和游标。请参阅thisthis博客文章,这将帮助您更好地理解光标的想法。


What's the logic here?

Are we expected to hack it like that?

不,理想情况下我们不会被期望破解并忘记它。这将在项目中留下技术债务,从长远来看,这可能会导致更多问题。您可以考虑实现自己的函数来返回连接对象。您将在 array-connection 的实现中了解如何做到这一点。在 graphql-relay-js 中。

Is it expected the return all the results?

同样,这取决于问题。


What if I used FB DataLoader and Redis? Would that change anything about that logic?

您可以使用 facebook dataloader 库来缓存和批处理您的查询。 Redis 是缓存结果的另一种选择。如果您加载 (1) 使用 dataloader 的所有项目或将所有项目存储在 Redis 中并且 (2) 这些项目是轻量级的,则您可以轻松创建所有项目的数组(遵循 KISS 原则)。如果项目很重,创建数组可能是一个昂贵的操作。

关于relayjs - 使用连接和分页时GraphQL与数据库之间的关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37583686/

相关文章:

flowtype - 需要帮助理解一些 Flow 类型的语法

javascript - 您如何为针对 ORM 的分页定义中继连接?

javascript - 是否有任何工具可以动态生成 graphQl 模式字符串?

javascript - GraphQL 嵌套查询定义

javascript - React-router-relay 与 Relay 模式不一致吗?

django - 基于 Graphene-Django 中继游标的分页不适用于动态数据

reactjs - Relay、Redux、Apollo 与 GraphQL 和 React-Native

graphql - 预期未定义为 GraphQL 叶类型

graphql - 如何限制查询自省(introspection)

graphql - 如何在 graphql 中重用解析器