如何对 Trello api 响应进行分页?

How to paginate Trello api response?

我正在使用 Trello 的 API 来拉动看板和它们的卡片。

我注意到我正在拉的其中一个板目前接近千张卡片,所以我想知道如何对结果进行分页?

我尝试使用 since 属性并将最后一张卡片的更新时间输入其中,但之后我得到的结果为零,所以我一定是做错了什么。

api 文档并没有说太多,我试过的 API 响应非常混乱:

/boards/xyz/cards?limit=1&before=2015-1-1

returns activity 是 指定日期之后的卡片。

"dateLastActivity"=>"2015-02-03T17:51:23.253Z",

并且没有其他日期字段可以用来继续分页。

您的评价是对的。 beforesince 参数在卡片创建日期运行。因为我们使用标准 Mongo ID,所以您实际上可以从卡片 ID 中得出卡片创建日期。 (这是一个这样的工具:https://steveridout.github.io/mongo-object-time/

为方便起见,Trello 还允许您将卡 ID 传递给 beforesince 参数,我们将为您使用日期。通过大量卡片进行分页的推荐方法是重复相同的查询,并使用这些参数向前或向后移动。

因此,由于 API 确实无法像您期望的那样工作,所以我至少在此处记录了这一点。

我用卡片 ABC、...、M 创建了一个测试板,所以我可以在上面进行测试。

首先,抓取所有卡片按预期工作。

api.find(:boards, '56af532ae7a74a5fcac32e66').cards.map { |c| [c.name, c.id] }

=> [
 ["A", "56af53367f15b163c0e345fd"],
 ["B", "56af533783d4fccc1cce3941"],
 ["C", "56af533831727db409451c9e"],
 ["D", "56af53397bf672bb56c7c536"],
 ["E", "56af5339f5e67cf6bcc7323b"],
 ["F", "56af533ac0aa02de54ab881a"],
 ["G", "56af533b212b095266ebb506"],
 ["H", "56af533e11992f20f375fca1"],
 ["I", "56af533fc1775129aaa7028b"],
 ["J", "56af5345f81227a7a1cc3a35"],
 ["K", "56af5345e36b3d3c45b16967"],
 ["L", "56af534d964b6c4aa93d4aca"],
 ["M", "56af534e768610ff67c781ce"]
]

注意:卡片的顺序不是按照创建时间,而是按照它们在面板中从左列到右列以及从上到下的出现顺序。

限制

好的,是时候开始分页了。我们只拿第一张牌好吗?

board.cards(limit: 1).map { |c| [c.name, c.id] }

=> [["M", "56af534e768610ff67c781ce"]]

糟糕,API return 是最后一个元素。绝对出乎意料。接下来让我们玩after/before。

之前

让我们在最后一个之前抢卡。

board.cards(limit: 1, before: '56af534e768610ff67c781ce').map { |c| [c.name, c.id] }

=> [["L", "56af534d964b6c4aa93d4aca"]]

效果不错,LM之前。

之后

如果我们在最后一张之后抓一张牌,响应应该是空的,对吧?

board.cards(limit: 1, after: '56af534e768610ff67c781ce').map { |c| [c.name, c.id] }

=> [["M", "56af534e768610ff67c781ce"]]

嗯,什么?那如果我抓两张卡会怎样?

board.cards(limit: 2, after: '56af534e768610ff67c781ce').map { |c| [c.name, c.id] }

=> [
  ["L", "56af534d964b6c4aa93d4aca"], 
  ["M", "56af534e768610ff67c781ce"]
]

这违背了任何逻辑。肯定不能从头到尾遍历一遍,因为卡片列表是没有尽头的。

返回分页

在这种情况下,我们将不得不以相反的顺序检查卡片。只需指定 limit 即可,因为默认情况下我们将按相反的顺序进行。 (这很有意义,对吧?)

api.find(:boards, '56af532ae7a74a5fcac32e66').cards(limit: 5).map { |c| [c.name, c.id] }

=> [
 ["I", "56af533fc1775129aaa7028b"], 
 ["J", "56af5345f81227a7a1cc3a35"], 
 ["K", "56af5345e36b3d3c45b16967"], 
 ["L", "56af534d964b6c4aa93d4aca"], 
 ["M", "56af534e768610ff67c781ce"]
]

不要让这些项目的顺序欺骗了您!仍然是它们 出现 在面板中的顺序,它们不是按创建时间排序的。如果我在其列中移动 M 卡片,使其正好位于 L 上方,则 API 将按相反的顺序 return 它们。

现在的问题是,如何从列表中抓取旧卡?正如另一个答案所说,ID 是时间戳,所以我们只需按 ID 排序并选择最低的并继续分页。

注意:如果您的速度很快,您可以在同一秒内创建多张卡片,因此 ID 的顺序可能不正确,因为它们只使用秒数,而不是微秒数。但这并不妨碍我们进行分页。

board.cards(limit: 5, before: '56af533fc1775129aaa7028b').map { |c| [c.name, c.id] }

=> [
  ["D", "56af53397bf672bb56c7c536"], 
  ["E", "56af5339f5e67cf6bcc7323b"], 
  ["F", "56af533ac0aa02de54ab881a"], 
  ["G", "56af533b212b095266ebb506"], 
  ["H", "56af533e11992f20f375fca1"]
]

太棒了,我们正在看下一页,让我们看最后一页吧。

board.cards(limit: 5, before: '56af53397bf672bb56c7c536').map { |c| [c.name, c.id] }

=> [
  ["A", "56af53367f15b163c0e345fd"],
  ["B", "56af533783d4fccc1cce3941"],
  ["C", "56af533831727db409451c9e"]
]

是的,所以最后一页包含的卡片少于限制,所以我们知道它是最后一页。万岁! (如果它等于页面大小,我们会发现下一个响应是空的)