使用Node.js在DynamoDB中进行分页吗?

use*_*811 4 pagination amazon-web-services node.js amazon-dynamodb

我已经阅读了有关分页的AWS文档:http : //docs.aws.amazon.com/amazondynamodb/latest/developerguide/QueryAndScan.html#ScanQueryLimit

正如他们的文档指定的那样:

在响应中,DynamoDB返回在Limit值范围内的所有匹配结果。例如,如果您发出“限制”值为6且没有过滤表达式的查询或扫描请求,则DynamoDB会返回表中与请求中指定的关键条件匹配的前六个项目(或仅返回前六个项目)。在没有过滤器的情况下扫描)

这意味着,假设我有一个Questions带有名为的属性的调用表(该属性difficulty可以采用从0到的任何数值2),我可能会遇到以下难题:

  • 客户提出要求,认为 GET /questions?difficulty=0&limit=3
  • 我将其转发3给DynamoDB查询,该查询可能返回0项目,因为集合中的前3个可能不是difficulty == 0
  • 然后,我必须执行一个新查询以获取更多questions符合该条件的查询,而不知道我可能会返回重复项

然后如何根据查询正确分页?在具有正确偏移量的情况下,可以获得与我要求的结果一样多的结果

Ros*_*wal 21

使用异步/等待。

const getAllData = async (params) => { 

    console.log("Querying Table");
    let data = await docClient.query(params).promise();

    if(data['Items'].length > 0) {
        allData = [...allData, ...data['Items']];
    }

    if (data.LastEvaluatedKey) {
        params.ExclusiveStartKey = data.LastEvaluatedKey;
        return await getAllData(params);

    } else {
        return data;
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在使用全局变量allData来收集所有数据。

调用此函数包含在 try-catch 中

try {

        await getAllData(params);
        console.log("Processing Completed");

        // console.log(allData);

    } catch(error) {
        console.log(error);
    }
Run Code Online (Sandbox Code Playgroud)

我在Lambda 中使用它,它工作正常。

这里的文章真的对我有帮助和指导。谢谢。


Ant*_*ton 11

我希望你明白了。所以以防万一其他人可能会发现它有用。AWS 有 QueryPaginator/ScanPaginator ,如下所示:

const paginator = new QueryPaginator(dynamoDb, queryInput);

for await (const page of paginator) {
    // do something with the first page of results
    break
}
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请访问https://github.com/awslabs/dynamodb-data-mapper-js/tree/master/packages/dynamodb-query-iterator

paginateXXXX2022-05-19:对于 AWS SDK v3,请参阅此博客文章https://aws.amazon.com/blogs/developer/pagination-using-async-iterators-in-modular-aws-sdk-for-的使用方法javascript/


EES*_*EES 7

避免使用递归来防止调用堆栈溢出。扩展@Roshan Khandelwal 方法的迭代解决方案:

const getAllData = async (params) => {
  const _getAllData = async (params, startKey) => {
    if (startKey) {
      params.ExclusiveStartKey = startKey
    }
    return this.documentClient.query(params).promise()
  }
  let lastEvaluatedKey = null
  let rows = []
  do {
    const result = await _getAllData(params, lastEvaluatedKey)
    rows = rows.concat(result.Items)
    lastEvaluatedKey = result.LastEvaluatedKey
  } while (lastEvaluatedKey)
  return rows
}
Run Code Online (Sandbox Code Playgroud)


and*_*amm 6

这是一个如何在Node.js中从DynamoDB scan(也可以很容易地对其进行修改query)的分页结果集中进行迭代的示例。

您可以保存LastEvaluatedKey状态服务器端,然后将标识符传递回您的客户端,该标识符将与下一个请求一起发送,并且服务器将在下一个请求中将该值传递ExclusiveStartKey给DynamoDB。

const AWS = require('aws-sdk');
AWS.config.logger = console;

const dynamodb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });

let val = 'some value';

let params = {
  TableName: "MyTable",
  ExpressionAttributeValues: {
    ':val': {
      S: val,
    },
  },
  Limit: 1000,
  FilterExpression: 'MyAttribute = :val',
  // ExclusiveStartKey: thisUsersScans[someRequestParamScanID]
};

dynamodb.scan(scanParams, function scanUntilDone(err, data) {
  if (err) {
    console.log(err, err.stack);
  } else {
    // do something with data

    if (data.LastEvaluatedKey) {
      params.ExclusiveStartKey = data.LastEvaluatedKey;

      dynamodb.scan(params, scanUntilDone);
    } else {
      // all results scanned. done!
      someCallback();
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

  • 我已经添加了异步/等待版本的答案@JohnSmith (2认同)

Ale*_*kis 4

查询和扫描操作返回LastEvaluatedKey其响应。如果没有并发插入,只要您迭代调用 Query/Scan 并将 ExclusiveStartKey 设置为前一个调用的 LastEvaluatedKey,您就不会错过项目,也不会多次遇到项目。