我已阅读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
,而不知道我可能会返回重复项如何根据查询正确分页?我得到的结果与我要求的结果一样,同时具有正确的偏移量
答案 0 :(得分:5)
以下是如何迭代分页结果集的示例
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();
}
}
});
答案 1 :(得分:4)
避免使用递归来防止调用堆栈溢出。扩展@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
}
答案 2 :(得分:3)
查询和扫描操作会在其回复中返回<style>
<?php include 'CSS/style.css'; ?>
</style>
。如果没有并发插入,只要您重复调用Query / Scan并将ExclusiveStartKey设置为上一次调用的LastEvaluatedKey,您就不会错过项目,也不会多次遇到项目。
答案 3 :(得分:1)
使用异步/等待。
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;
}
}
我正在使用全局变量 allData 来收集所有数据。
调用此函数包含在try-catch中
try {
await getAllData(params);
console.log("Processing Completed");
// console.log(allData);
} catch(error) {
console.log(error);
}
我正在 Lambda 中使用它,并且效果很好。
文章here确实为我提供了指导。谢谢。
答案 4 :(得分:1)
我希望你明白了。所以以防万一其他人可能会发现它有用。 AWS 的 QueryPaginator/ScanPaginator 如下所示:
const paginator = new QueryPaginator(dynamoDb, queryInput);
for await (const page of paginator) {
// do something with the first page of results
break
}
在https://github.com/awslabs/dynamodb-data-mapper-js/tree/master/packages/dynamodb-query-iterator
查看更多详情答案 5 :(得分:0)
您可以按难度创建索引索引,并在查询集KeyConditionExpression上设置难度为0。
var params = {
TableName: questions,
IndexName: 'difficulty-index',
KeyConditionExpression: 'difficulty = :difficulty ',
ExpressionAttributeValues: {':difficulty':0}
}
答案 6 :(得分:0)
用于在dynamodb扫描中创建分页
var params = {
"TableName" : "abcd",
"FilterExpression" : "#someexperssion=:someexperssion",
"ExpressionAttributeNames" : {"#someexperssion":"someexperssion"},
"ExpressionAttributeValues" : {":someexperssion" : "value"},
"Limit" : 20,
"ExclusiveStartKey" : {"id": "9ee10f6e-ce6d-4820-9fcd-cabb0d93e8da"}
};
DB.scan(params).promise();
此查询上次执行时间返回的ExclusiveStartKey是LastEvaluatedKey
答案 7 :(得分:0)
使用异步/等待,在等待中返回数据。 详细阐述@Roshan Khandelwal的答案。
const getAllData = async (params, allData = []) => {
const data = await dynamodbDocClient.scan(params).promise()
if (data['Items'].length > 0) {
allData = [...allData, ...data['Items']]
}
if (data.LastEvaluatedKey) {
params.ExclusiveStartKey = data.LastEvaluatedKey
return await getAllData(params, allData)
} else {
return allData
}
}
在try / catch中调用:
try {
const data = await getAllData(params);
console.log("my data: ", data);
} catch(error) {
console.log(error);
}
答案 8 :(得分:0)
您还可以使用递推代替全局变量来实现此目的,例如:
<button onclick="add()">click</button><br>
<div id="values"></div>
然后您可以简单地将其命名为:
const getAllData = async (params, allData = []) => {
let data = await db.scan(params).promise();
return (data.LastEvaluatedKey) ?
getAllData({...params, ExclusiveStartKey: data.LastEvaluatedKey}, [...allData, ...data['Items']]) :
[...allData, ...data['Items']];
};