构建分页光标

F21*_*F21 5 pagination cursor cursor-position

我有活动存储在图形数据库中.在某些情况下,多个活动被分组并聚合为1个活动.

已处理的活动Feed可能如下所示:

Activity 1

Activity 2

Grouped Activity
  Activity 3
  Activity 4

Activity 5
Run Code Online (Sandbox Code Playgroud)
  • 活动具有更新的时间戳和唯一ID.

  • 活动按其更新时间排序,如果是分组活动,则使用其子活动中的最新更新时间.

  • 活动可以插入列表中的任何位置(例如,如果我们开始关注某人,他们过去的活动将被插入到列表中).

  • 可以从列表中的任何位置删除活动.

  • 由于数据量大,使用带有微秒的时间戳仍然可能导致冲突(2个项目可以具有相同的时间戳).

  • 游标标识符应该是唯一且稳定的.添加和删​​除Feed项不应更改标识符.

我想介绍基于光标的分页,以允许客户端通过类似于twitter的 Feed分页.似乎没有太多关于它们是如何构建的信息,因为我只发现这篇博文在谈论实现它们.但是,如果光标的标识符恰好指向已删除的项目,则似乎存在问题.

有了上述内容,我如何生成一个可用作上述光标的标识符?最初,我考虑将时间戳与唯一ID组合:1371813798111111.myuniqueid.但是,如果1371813798111111.myuniqueid删除了项目,我可以获取带有1371813798111111时间戳的项目,但无法确定哪个项目应该以我应该开始的时间戳.

我的另一种方法是为每个Feed结果分配一个递增的数字.由于数字是递增的并且按顺序,如果缺少数字/ id,我可以选择下一个.但是,这样做的问题是,如果我开始在Feed中间删除并添加Feed项,则游标ID会发生变化.我遇到这个问题的一个解决方案是每个数字之间存在巨大差距,但很难确定如何以确定的方式将新项目添加到每个数字之间的空间.此外,随着新项目的增加,以及填补的空白,我们最终会遇到同样的问题.

简单地说,如果我有一个项目列表,可以在列表中的任何位置添加和删除项目,那么为每个列表项生成id的最佳方法是,如果删除了id的项目,我仍然可以确定它在列表中的位置

小智 2

您需要有额外的(或现有的)列,该列对于目标表中每个新添加的行依次增加。我们将此列称为seq_id

当客户端第一次请求游标时:

GET /api/v1/items?sort_by={sortingFieldName}&size={count}
Run Code Online (Sandbox Code Playgroud)

其中 sortingFieldName 是我们应用排序的字段名称

幕后发生了什么:

SELECT * FROM items
WHERE ...            // apply search params
ORDER BY sortingFieldName, seq_id
LIMIT :count
Run Code Online (Sandbox Code Playgroud)

回复:

{
    "data": [...],
    "cursor": {
        "prev_field_name": "{result[0].sortingFieldName}",
        "prev_id": "{result[0].seq_id}",
        "nextFieldName": "{result[count-1].sortingFieldName}",
        "next_id": "{result[count-1].seq_id}",
        "prev_results_link": "/api/v1/items?size={count}&cursor=bw_{prevFieldName}_{prevId}",
        "next_results_link": "/api/v1/items?size={count}&cursor=fw_{nextFieldName}_{nextId}"       
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我们检索的行数少于 count 行,则游标的下一个将不会出现在响应中。

如果请求中没有游标或没有要返回的数据,游标的前一部分将不会出现在响应中。

当客户端再次执行请求时 - 他需要使用游标。向前光标:

GET /api/v1/items?size={count}&cursor=fw_{nextFieldName}_{nextId}
Run Code Online (Sandbox Code Playgroud)

幕后发生了什么:

SELECT * FROM items
WHERE ...            // apply search params
AND ((fieldName = :cursor.nextFieldName AND seq_id > :cursor.nextId) OR 
      fieldName > :cursor.nextFieldName)
ORDER BY sortingFieldName, seq_id
LIMIT :count
Run Code Online (Sandbox Code Playgroud)

或向后光标:

GET /api/v1/items?size={count}&cursor=fw_{prevFieldName}_{prevId}
Run Code Online (Sandbox Code Playgroud)

幕后发生了什么:

SELECT * FROM items
WHERE ...            // apply search params
AND ((fieldName = :cursor.prevFieldName AND seq_id < :cursor.prevId) OR 
      fieldName < :cursor.prevFieldName)
ORDER BY sortingFieldName DESC, seq_id DESC
LIMIT :count
Run Code Online (Sandbox Code Playgroud)

响应将与前一个类似