如果结果集可以更改,如何使用RESTful API实现强大的分页?

时间:2011-12-13 10:03:34

标签: scala rest backbone.js

我正在实现一个RESTful API,它将Orders作为资源公开,并通过结果集支持分页:

GET /orders?start=1&end=30

其中分页的订单按ordered_at时间戳排序,降序。这基本上是SO问题Pagination in a REST web application中的#1方法。

如果用户请求订单的第二页(GET /orders?start=31&end=60),则服务器只需重新​​查询订单表,再次按ordered_at DESC排序并返回位置31到60的记录。

我遇到的问题是:如果在用户查看记录时结果集发生变化(例如添加了新订单)会发生什么?在添加新订单的情况下,用户将在第二页结果的第一个位置看到旧订单#30(因为相同的订单现在是#31)。更糟糕的是,在删除的情况下,用户在第二页(#31)的第一个位置看到旧订单#32,并且根本看不到旧订单#31(现在#30)。

如果不以某种方式使RESTful服务器有状态(urg)或为每个客户端构建一些分页智能,我无法看到解决方案......有哪些已建立的技术可以解决这个问题?

为了完整性:我的后端是用Scala / Spray / Squeryl / Postgres实现的;我正在构建两个前端客户端,一个在backbone.js中,另一个在Python Django中。

5 个答案:

答案 0 :(得分:5)

我这样做的方法是将索引从旧到新。所以他们永远不会改变然后在没有任何启动参数的情况下查询时,返回最新页面。此外,响应应包含指示包含哪些元素的索引,因此您可以计算下一个较旧页面所需的索引。虽然这不是你想要的,但对我来说似乎是最简单,最干净的解决方案。

初始请求GET /orders?count=30返回:

{
  "start"=1039;
  "count"=30;
  ...//data
}

消费者计算出他想要请求:

下一个请求: GET /orders?start=1009&count=30然后返回:

{
  "start"=1009;
  "count"=30;
  ...//data
}

您还可以返回指向下一页的链接,而不是原始索引:

{
  "next"="/orders?start=1009&count=30";
}

如果在中间插入或删除项目,则此方法会中断。在这种情况下,您应该使用一些自动递增持久值而不是索引。

答案 1 :(得分:1)

可悲的事实是,我看到的所有网站都在这个意义上“破碎”,所以一定不可能有一个简单的方法来实现这一目标。

快速解决方法可能会颠倒顺序,因此项目的位置是绝对的,并且与新添加的内容保持不变。在您的首页,您可以提供最新的索引,以确保从那里开始一致的导航。

  • 优点:相同的网址提供相同的结果
  • 缺点:没有明显的方法来获取最新元素......也许你可以使用负面索引并将结果页面重定向到绝对索引。

答案 2 :(得分:1)

使用RESTFUL API,应用程序状态应该在客户端中。在这里,应用程序状态应该是某种时间戳或版本号,告诉您何时开始查看数据。在服务器端,您将需要某种形式的审计跟踪,这是正确的服务器数据,因为它不依赖于是否有客户端以及他们做了什么。至少,它应该知道数据上次更改的时间。这里与REST没有矛盾。

您可以在get中添加版本参数。当客户端首先需要页面时,通常不会发送版本。服务器回复包含一个。例如,如果对下一页/其他页面的回复中有链接,则这些链接包含& version = ...客户端应在需要另一页时发送该版本。

当服务器收到某个版本的请求时,它至少应该知道自客户端开始查看以来数据是否已更改,并且取决于您拥有哪种审计跟踪,以及它们的更改方式。如果没有,它会正常回答,传输相同的版本号。如果有,它至少可以告诉客户。根据它对数据如何变化的了解程度,它可能会相应地回复数据。

举个例子,假设您收到了一个包含start,end,version的请求,并且您知道由于版本是最新的,因此删除了3行。您可以使用start-3,end-3,new version发送重定向。

答案 3 :(得分:1)

WebSockets可以做到这一点。您可以使用pusher.com之类的内容来捕获对数据库的实时更改,并将更改传递给客户端。然后,您可以绑定不同的推送事件以使用模型和集合。

答案 4 :(得分:0)

只是把它扔出去。请随时告诉我它是否完全错误,为什么会这样。

此方法尝试使用 left_off 变量进行排序,而不使用偏移量。

考虑您需要按时间戳order_at DESC进行排序。 所以当我要求第一个结果集时 它是

SELECT * FROM Orders ORDER BY order_at DESC LIMIT 25;

正确? 当你要求第一页时就是这种情况(就URL而言,可能是没有任何

的请求) ?

yoursomething.com/orders的限制= 25安培; left_off = $时间戳

然后收到您的数据集。只需获取上次查看项目的时间戳即可。 2015-12-21 13:00:49

现在请求接下来的25个项目转到: yoursomething.com/orders?limit=25&left_off=2015-12-21 13:00:49 (最后查看时间戳)

在Sql中,您只需进行相同的查询,并说出时间戳等于或小于$ left_off的位置

SELECT * FROM (SELECT * FROM Orders ORDER BY order_at DESC) as a 
WHERE a.order_at < '2015-12-21 13:00:49' LIMIT 25;

您应该从上次看到的项目中获得下一个25项。

对于那些看到这个答案的人。如果这种方法是相关的,甚至可能是首选,请评论。谢谢。