首页 > 解决方案 > 如何为 GraphQL 连接实现后端?

问题描述

在 GraphQL 中,推荐的分页方式是使用这里描述的连接。我理解这种用法​​的原因和优点,但我需要一个如何实施它的建议。

应用程序的服务器端在 SQL 数据库(在我的例子中是 Postgres)之上工作。一些 GraphQL 连接字段具有用于指定排序的可选参数。现在知道了 GraphQL 查询中的排序列和游标,我该如何构建 SQL 查询?当然它应该是有效的——如果有一个用于排序列组合的 SQL 索引索引,则应该使用它。

问题是 SQL 不知道 GraphQL 游标之类的东西——我们不能告诉它选择某行之后的所有行。只有 WHERE、OFFSET 和 LIMIT。从我的角度来看,我似乎需要首先基于游标选择一行,然后使用该行中排序列的值构建第二个 SQL 查询以指定复杂的 WHERE 子句 - 不确定数据库是否会使用这种情况下的索引。

困扰我的是,我找不到任何关于这个主题的文章。这是否意味着在实现 GraphQL 服务器时通常不使用 SQL 数据库?那么应该使用什么数据库呢?GraphQL 对连接字段的查询通常如何转换为对底层数据库的查询?

编辑:或多或少是我自己想出的。问题是如何扩展它以支持排序以及如何使用数据库索引有效地实现它。

标签: sqlsortingpaginationgraphql

解决方案


这里的诀窍是,作为服务器实现者,光标实际上可以是您想要编码为字符串的任何值。我见过的大多数示例都是经过 base64 编码的,有点不透明,但并非必须如此。(例如,尝试对链接中星球大战示例中的光标进行 base64 解码。)

假设您的 GraphQL 架构看起来像

enum ThingColumn { FOO BAR }
input ThingFilter {
  foo: Int
  bar: Int
}
type Query {
  things(
    filter: ThingFilter,
    sort: ThingColumn,
    first: Int,
    after: String
  ): ThingConnection
}

您的第一个查询可能是

query {
  things(filter: { foo: 1 }, sort: BAR, first: 2) {
    edges {
      node { bar }
    }
    pageInfo {
      endCursor
      hasNextPage
    }
  }
}

这本身可以相当直接地转化为 SQL 查询,例如

SELECT bar FROM things WHERE foo=1 ORDER BY bar ASC LIMIT 2;

现在,当您遍历每个项目时,您可以只使用其偏移量的字符串版本作为光标;这是规范完全允许的。

{
  "data": {
    "things": {
      "edges": [
        { "node": { "bar": 17 } },
        { "node": { "bar": 42 } }
      ],
      "pageInfo": {
        "endCursor": "2",
        "hasNextPage": true
      }
    }
  }
}

然后,当下一个查询显示 时after: "2",您可以将其转回 SQLOFFSET并重复查询。

如果您正在尝试构建一个通用 GraphQL 接口,该接口可以转换为相当通用的 SQL 查询,那么创建索引以使每个查询都“快速”是不可能的。与其他情况一样,您需要根据需要弄清楚您的常见和/或慢查询是什么CREATE INDEX。您也许可以将架构中的选项限制为您知道可以索引的内容:

type Other {
  things(first: Int, after: String): ThingConnection
}
query OtherThings($id: ID!, $cursor: String) {
  node(id: $id) {
    ... on Other {
      things(first: 100, after: $cursor) { ... FromAbove }
    }
  }
}
SELECT * FROM things WHERE other_id=? ORDER BY id LIMIT ?;
CREATE INDEX things_other ON things(other_id);

推荐阅读