22

我想将亚马逊 Dynamo DB 与 rails 一起使用。但我还没有找到实现分页的方法。

我将AWS::Record::HashModel用作 ORM。

这个 ORM 支持这样的限制:

People.limit(10).each {|person| ... } 

但我不知道如何在 Dynamo DB 中实现以下 MySql 查询。

SELECT * 
  FROM  `People` 
 LIMIT 1 , 30
4

5 回答 5

43

您使用 LIMIT 发出查询。如果返回的子集不包含完整的表,LastEvaluatedKey则返回一个值。您将此值用作ExclusiveStartKey下一个查询中的值。等等...

来自DynamoDB 开发人员指南

于 2012-02-02T04:04:07.090 回答
2

You can provide 'page-size' in you query to set the result set size. The response of DynamoDB contains 'LastEvaluatedKey' which will indicate the last key as per the page size. If response does't contain 'LastEvaluatedKey' it means there are no results left to fetch. Use the 'LastEvaluatedKey' as 'ExclusiveStartKey' while fetching next time.

I hope this helps.

DynamoDB Pagination

于 2017-09-27T06:10:56.823 回答
1

这是一个简单的复制粘贴运行概念证明 (Node.js),用于使用 dynamodb 进行无状态正向/反向导航。总之; 每个响应都包含导航历史记录,允许用户明确且一致地请求下一页或上一页(当存在下一个/上一个参数时):

GET /accounts                -> first page
GET /accounts?next=A3r0ijKJ8 -> next page
GET /accounts?prev=R4tY69kUI -> previous page

注意事项:

  1. 如果您的 id 很大和/或用户可能会进行大量导航,那么下一个/上一个参数的潜在大小可能会变得太大。
  2. 是的,您确实必须存储整个反向路径 - 如果您只存储前一页标记(根据其他一些答案),您将只能返回一页。
  3. 它不会在中途处理更改 pageSize,请考虑将 pageSize 烘焙到下一个/上一个值。
  4. base64 编码下一个/上一个值,你也可以加密。
  5. 扫描效率低下,虽然这适合我目前的要求,但并不适合所有人!
// demo.js
const mockTable = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
const getPagedItems = (pageSize = 5, cursor = {}) => {

  // Parse cursor
  const keys = cursor.next || cursor.prev || [] // fwd first
  let key = keys[keys.length-1] || null // eg ddb's PK

  // Mock query (mimic dynamodb response)
  const Items = mockTable.slice(parseInt(key) || 0, pageSize+key)
  const LastEvaluatedKey = Items[Items.length-1] < mockTable.length 
                            ? Items[Items.length-1] : null

  // Build response
  const res = {items:Items}
  if (keys.length > 0) // add reverse nav keys (if any)
    res.prev = keys.slice(0, keys.length-1)
  if (LastEvaluatedKey) // add forward nav keys (if any)
    res.next = [...keys, LastEvaluatedKey]
  
  return res
}

// Run test ------------------------------------
const runTest = () => {
  const PAGE_SIZE = 6
  let x = {}, i = 0

  // Page to end
  while (i == 0 || x.next) {
    x = getPagedItems(PAGE_SIZE, {next:x.next})
    console.log(`Page ${++i}: `, x.items)
  }

  // Page back to start
  while (x.prev) {
    x = getPagedItems(PAGE_SIZE, {prev:x.prev})
    console.log(`Page ${--i}: `, x.items)
  }
}
runTest()
于 2020-10-02T23:09:14.253 回答
0

我遇到了类似的问题。

通用的分页方法是,使用“起始索引”或“起始页”和“页长”。 

基于“ExclusiveStartKey”和“LastEvaluatedKey”的方法非常特定于 DynamoDB。

我觉得这个 DynamoDB 特定的分页实现应该对 API 客户端/UI 隐藏。

此外,如果应用程序是无服务器的,使用 Lambda 之类的服务,将无法维护服务器上的状态。另一方面是客户端实现会变得非常复杂。

我提出了一种不同的方法,我认为这是通用的(而不是特定于 DynamoDB)

当 API 客户端指定起始索引时,从表中获取所有键并将其存储到数组中。

从客户端指定的数组中找出起始索引的键。

使用 ExclusiveStartKey 并获取页面长度中指定的记录数。

如果起始索引参数不存在,则不需要上述步骤,我们不需要在扫描操作中指定 ExclusiveStartKey。

该解决方案有一些缺点 -

当用户需要使用起始索引进行分页时,我们将需要获取所有键。

我们将需要额外的内存来存储 Id 和索引。额外的数据库扫描操作(一个或多个获取键)

但我觉得对于使用我们 API 的客户来说,这将是一种非常简单的方法。向后扫描将无缝工作。如果用户想要查看“第 n 个”页面,这将是可能的。

于 2019-04-03T13:18:24.103 回答
-1

事实上,我遇到了同样的问题,我注意到了这一点LastEvaluatedKey并且ExclusiveStartKey效果不佳,尤其是在使用时,Scan所以我解决了这样的问题。

  1. GET/?page_no=1&page_size=10 =====> 第一页
  2. 响应将包含记录计数和前 10 条记录
  3. 重试并增加页数,直到所有记录都来了。

代码在
PS下面:我正在使用 python

first_index = ((page_no-1)*page_size)
second_index = (page_no*page_size)
if (second_index > len(response['Items'])):
    second_index = len(response['Items'])
return {
'statusCode': 200,
'count': response['Count'],
'response': response['Items'][first_index:second_index]
    
}
于 2021-04-02T05:54:28.560 回答