Database 如何从数据库中获取用于Graphql分页的游标?

Database 如何从数据库中获取用于Graphql分页的游标?,database,graphql,graphql-js,cursor-position,resolver,Database,Graphql,Graphql Js,Cursor Position,Resolver,我在获取用于在GraphQL中解析数据库分页结果的真正游标时遇到了严重的问题。无论我使用哪种数据库(SQL,例如mysql或NoSQL文档,例如mongodb),我似乎都无法获得游标或类似游标的对象 也许我错过了一些基本的概念,但在搜索我的b。。。我开始严重怀疑官方的GraphQL分页文档 是基于任何真实的生活经验 我的问题是:如何从这样的SQL查询中获得与游标非常相似的内容 SELECT authors.id, authors.last_name, authors.created_at FR

我在获取用于在GraphQL中解析数据库分页结果的真正游标时遇到了严重的问题。无论我使用哪种数据库(SQL,例如mysql或NoSQL文档,例如mongodb),我似乎都无法获得游标或类似游标的对象

也许我错过了一些基本的概念,但在搜索我的b。。。我开始严重怀疑官方的GraphQL分页文档

是基于任何真实的生活经验

我的问题是:如何从这样的SQL查询中获得与游标非常相似的内容

SELECT authors.id, authors.last_name, authors.created_at FROM authors
ORDER BY authors.last_name, author.created_at
LIMIT 10
OFFSET 20
我知道,不应该使用基于偏移量的分页,相反,基于光标的导航被认为是一种补救方法。而且我肯定想治愈我的申请从抵消疾病。但为了做到这一点,我需要能够从某个地方检索光标

我也理解(忘记我在哪里读到的)主键也不应该用于分页


所以,我被困在这里。

我认为你因为提出了一个好问题而被否决了。第一个/最后一个/之前/之后的概念很难在SQL中实现

我一直在为同样的问题伤脑筋。分页文档没有说明在应用自定义顺序语句时如何定义游标

我也没有在网上找到一个全面的解决方案。我在一些帖子中发现,人们正在解决这个问题,但答案只是部分正确或部分完整(只需对ID字段进行base64编码,使光标看起来像是要回答的问题,但这并没有说明查询在计算光标时必须做些什么)。此外,任何涉及行数的解决方案都非常难看,不适用于不同的SQL方言。让我们换一种方式来尝试

快速免责声明,这将是一篇相当全面的文章,但是如果您的后端使用一个像样的查询生成器,那么您可以从技术上编程一个方法,用于实现将GraphQL中继到任何现有查询上所需的第一个/最后一个/之前/之后分页。唯一的要求是,您正在排序的所有表都有一列,该列唯一地表示记录的默认顺序(通常,如果主键是一个整数,并且使用的是自动生成的ID,则可以使用该ID,即使从技术上讲,按主键对表进行排序并不总是产生与无序返回表相同的结果)

暂时不要考虑base64,只需假设ID是表示表的默认顺序的有效游标字段

你在网上找到的使用光标的答案通常是这样的

SELECT * FROM TABLE T
WHERE T.id > $cursorId;
好的,只要不将任何其他排序应用于查询,这对于获取光标后的所有条目非常有用。一旦使用了示例中的自定义排序,此建议就失效了

然而,其中的核心逻辑可以重新应用于带有排序的查询,但解决方案需要扩展。让我们尝试提出完整的算法


c后第一个n的算法(光标后第一个n节点)

节点或边与SQL术语中的行相同。(如果1行表示单个实体,例如1个作者)

光标是我们将开始返回同级行的行,无论是向前还是向后

给定的C是光标

A是与C进行比较的任何其他行

TAC都是行的表格

v w x y z是表T上的5列,当然AC都有这些列

算法必须根据游标对象(给定n)和提供的这5列的顺序来决定返回查询中是否包含A

 SELECT A FROM T
 WHERE A.v > C.v
 OR (A.v = C.v AND A.w > C.w)
 OR (A.v = C.v AND A.w = C.w AND A.x > C.x)
 OR (A.v = C.v AND A.w = C.w AND A.x = C.x AND A.y > C.y)
 OR (A.v = C.v AND A.w = C.w AND A.x = C.x AND A.y = C.y AND A.z > C.z)
 ORDER BY T.v ASC, T.w ASC, T.x ASC, T.y ASC, T.z ASC
 LIMIT n
让我们从一份订单开始

假设有1个顺序(v):(如果我们假设表默认按主键排序,那么至少应该有1个顺序) 要显示前n个记录,我们需要应用一个限制n,这很简单。困难的部分是在c之后的

对于仅由1个字段排序的表,该字段将归结为:

 SELECT A FROM T
 WHERE A.v > C.v
 ORDER BY T.v ASC
 LIMIT n
这应该显示v大于C的所有行,并删除v小于C的所有行,这意味着在C之前将不会有任何行。如果我们假设主键正确地表示自然顺序,那么 可以删除ORDER BY语句。然后此查询的可读性稍高的版本将变为:

 SELECT A FROM T
 WHERE A.id > $cursorIdGivenByClient
 LIMIT n
在这里,我们找到了一个最简单的解决方案,为一个“未排序”的表提供一个游标。这与处理游标的普遍接受的答案是一样的,但不完全

现在让我们看一个按两列排序的查询(vw):

我们从相同的
开始,其中A.v>C.v
,任何值v(A.v)小于第一个排序(C.v)的值C的行从输出结果中删除。但是,如果第一顺序v的列对A和C都具有相同的值,
A.v=C.v
我们需要查看第二顺序列,以查看是否仍允许在查询结果中显示A。如果
A.w>C.w

让我们继续讨论具有3种排序的查询:

 SELECT A FROM T
 WHERE A.v > C.v
 OR (A.v = C.v AND A.w > C.w)
 OR (A.v = C.v AND A.w = C.w AND A.x > C.x)
 ORDER BY T.v ASC, T.w ASC, T.x ASC
 LIMIT n
这与2个排序的逻辑相同,但要计算得更详细一些。如果第一列相同,我们需要查看第二列以确定谁是最大的。如果第二列也相同,我们需要查看第三列。认识到主键始终是ORDER BY语句中的最后一个排序列,这一点很重要,及
 SELECT A FROM T
 WHERE A.v > C.v
 OR (A.v = C.v AND A.w > C.w)
 OR (A.v = C.v AND A.w = C.w AND A.x > C.x)
 OR (A.v = C.v AND A.w = C.w AND A.x = C.x AND A.y > C.y)
 ORDER BY T.v ASC, T.w ASC, T.x ASC, T.y ASC
 LIMIT n
 SELECT A FROM T
 WHERE A.v > C.v
 OR (A.v = C.v AND A.w > C.w)
 OR (A.v = C.v AND A.w = C.w AND A.x > C.x)
 OR (A.v = C.v AND A.w = C.w AND A.x = C.x AND A.y > C.y)
 OR (A.v = C.v AND A.w = C.w AND A.x = C.x AND A.y = C.y AND A.z > C.z)
 ORDER BY T.v ASC, T.w ASC, T.x ASC, T.y ASC, T.z ASC
 LIMIT n
 SELECT A FROM T
 WHERE (A.v > C.v OR
           (A.v = C.v AND 
              (A.w > C.w OR
                   (A.w = C.w AND
                       (A.x > C.x OR
                           (A.x = C.x AND
                               (A.y > C.y OR
                                    (A.y = C.y AND
                                        (A.z > C.z)))))))))
 ORDER BY T.v ASC, T.w ASC, T.x ASC, T.y ASC, T.z ASC
 LIMIT n
 SELECT authors.id, authors.last_name, authors.created_at FROM authors
 ORDER BY authors.last_name, author.created_at
 $authorLastName, $authorCreatedAt =
      SELECT authors.last_name, authors.created_at from author where id = 15;
  SELECT a.id, a.last_name, a.created_at FROM authors a
  WHERE (a.last_name > $authorLastName OR
            (a.last_name = $authorLastName AND 
               (a.created_at > $authorCreatedAt OR
                    (a.created_at = $authorCreatedAt AND
                        (a.id > 15)))))
 ORDER BY a.last_name, a.created_at, a.id
 LIMIT 20;
  SELECT a.id, a.last_name, a.created_at FROM authors a
  WHERE (a.last_name > (select last_name from authors where id 15) OR
            (a.last_name = (select last_name from authors where id 15) AND 
               (a.created_at > (select created_at from authors where id 15)  OR
                    (a.created_at = (select created_at from authors where id 15) AND
                        (a.id > 15)))))
 ORDER BY a.last_name, a.created_at, a.id
 LIMIT 20;
 SELECT A FROM T
 WHERE (A.v < C.v OR
           (A.v = C.v AND 
              (A.w < C.w OR
                   (A.w = C.w AND
                       (A.x < C.x OR
                           (A.x = C.x AND
                               (A.y < C.y OR
                                    (A.y = C.y AND
                                        (A.z < C.z)))))))))
 ORDER BY T.v ASC, T.w ASC, T.x ASC, T.y ASC, T.z ASC
 LIMIT n