如何在 SQL 查询中使用排序方式实现 GraphQL 游标

How to implement GraphQL cursor in SQL query with sort by

我有一个数据库 table reviews idrating 其中 id 是自动递增的,rating 是 0 到 100 之间的整数。

我正在尝试在 GraphQL API 中创建基于游标的分页,但正在努力为 hasPreviousPagehasNextPage.

创建必要的查询

这是我的数据:

ID: 1, RATING: 50
ID: 2, RATING: 80
ID: 3, RATING: 20
ID: 4, RATING: 40
ID: 5, RATING: 60

下面是一个 GQL 查询示例:

reviews(first: 3)

哪个returns

ID: 1, RATING: 50
ID: 2, RATING: 80
ID: 3, RATING: 20

有 pageInfo

hasPreviousPage: false
hasNextPage: true

pageInfo 的查询将是

hasPreviousPage = SELECT COUNT(*) > 0 FROM reviews WHERE id < 0;
hasNextPage     = SELECT COUNT(*) > 0 FROM reviews WHERE id > 3;

我的问题出现在按评分排序时。 进行与之前类似的查询:

reviews(sort: "rating", first: 3)

哪个returns

ID: 3, RATING: 20
ID: 4, RATING: 40
ID: 1, RATING: 50

有 pageInfo

hasPreviousPage: false
hasNextPage: true

但是如何像以前一样为 hasPreviousPagehasNextPage 创建查询?

hasPreviousPage = SELECT COUNT(*) > 0 FROM reviews WHERE ???
hasNextPage     = SELECT COUNT(*) > 0 FROM reviews WHERE ???

在这种情况下 WHERE 子句应该是什么?子查询的查询是否需要复杂得多?我不确定我错过了什么。

您实际上不需要 hasPreviousPagehasNextPage 的任何数据库查询。 您需要应用 +2 技巧来实现此目的(假设您要为前后两种情况实施 hasPreviousPage)。

假设您有以下查询:

// `after` should be URL-safe encoded
// `id` must have a monotonic sort order, a ULID is a fine choice for an id
// if ULID is not an option for some reason, chose a different column that has a monotonicity to it, e.g. `created_at`
reviews(first: 3, after: "id:12345;sort_cols:user_id")

您想做的是查询前 5 条评论:

SELECT *
FROM reviews
WHERE id >= ?
ORDER BY ? ASC
LIMIT 5;

-- result: 12345, 12346, 12347, 12348, 12349
-- from the app return (after computing `pageInfo`): 12346, 12347, 12348

如果第一个结果的id与游标中的id相匹配,即12345则表示有上一页。 如果有上一页且 returned 行数为 4 或更少,hasNextPage: false。 如果 没有 上一页并且 returned 行数为 4 或更多,hasNextPage: true.

在 return 结果之前,请确保过滤掉与光标 ID (12345) 匹配的项目以及如果有下一页则额外的项目。

注意 SQL 必须正确生成。查询将根据分页的方向而改变(beforeafter)。如果你想支持范围请求,它也会变得更加复杂,即同时提供 beforeafter 的请求。

示例:

reviews(first: 3, before: "id:12345;sort_col:user_id")

这里要使用降序。 此外,您需要过滤 ids <= 来自光标的 id。

SELECT *
FROM reviews
WHERE id <= ?
ORDER BY ? DESC
LIMIT 5;

-- result: 12345, 12344, 12343, 12342, 12341
-- from the app return (after computing `pageInfo`): 12344, 12343, 12342