如何在rails中使用amazon Dynamo DB时实现分页

时间:2012-02-01 14:41:22

标签: ruby-on-rails nosql amazon-dynamodb

我想使用带有rails的amazon Dynamo DB。但我还没有找到实现分页的方法。

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

这个ORM支持这样的限制:

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

但我无法弄清楚如何在Dynamo DB中实现以下MySql查询。

SELECT * 
  FROM  `People` 
 LIMIT 1 , 30

5 个答案:

答案 0 :(得分:26)

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

来自DynamoDB Developer Guide

答案 1 :(得分:1)

您可以在查询中提供“页面大小”以设置结果集大小。 DynamoDB的响应包含“LastEvaluatedKey”,它将根据页面大小指示最后一个键。如果响应不包含'LastEvaluatedKey',则表示没有剩余的结果来获取。 在下次提取时使用'LastEvaluatedKey'作为'ExclusiveStartKey'。

我希望这会有所帮助。

DynamoDB Pagination

答案 2 :(得分:0)

我遇到了类似的问题。

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

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

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

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

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

  

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

     

从数组中查找起始索引的键,即   由客户指定。

     

使用ExclusiveStartKey并获取记录数,如下   在页面长度中指定。

     

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

此解决方案有一些缺点-

  

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

     

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

但是我觉得对于使用我们的API的客户来说,这将是非常简单的方法。向后扫描将无缝运行。如果用户希望看到“第n个”页面,则可以。

答案 3 :(得分:0)

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

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

注意事项:

  1. 如果您的ID很大,并且/或者用户可能进行了大量导航,那么next / prev参数的潜在大小可能会变得太大。
  2. 是的,您确实必须存储整个反向路径-如果仅存储前一页标记(根据其他答案),则只能返回上一页。
  3. 它不会在中途更改pageSize,请考虑将pageSize烘焙为next / prev值。
  4. base64对next / prev值进行编码,您也可以加密。
  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()

答案 4 :(得分:0)

事实上,我遇到了同样的问题,我注意到 LastEvaluatedKeyExclusiveStartKey 运行不佳,尤其是在使用 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]
    
}