在使用节点JS的DynamoDB查询中recursion提取所有项目

这可能是一个比DynamoDB特定问题更多的JS / Async问题 –

我想用Amazon的DynamoDB中的散列键获取表中的所有项目。 表中也有Range键。

我正在使用一个NodeJS库,它是AWS DynamoDB REST API的包装器。 – 节点 – DynamoDB

DynamoDB只会为每个查询返回1 MB的结果。 要提取结果提醒,它包括lastEvaluatedKey 。 我们可以在另一个查询中包含这个来获取另一个1 MB值的结果,等等…

我在编写recursionasynchronous函数时遇到了困难,它应该按顺序打到服务,直到我可以得到所有结果为止。 (表格永远不会超过10 MB用于我的用例,没有失控查询的机会)

一些伪代码的插图:

ddb.query('products', primarykey, {}, function(err,result){ //check err if(result && result.lastEvaluatedKey){ //run the query again var tempSet = result.items; //temporarily store result.items so we can continue and fetch remaining items. } else{ var finalSet = result.items; //figure out how to merge with items that were fetched before. } }); 

 var getAll = function(primarykey, cb) { var finalSet = [], nextBatch = function(lek) { ddb.query('products', primarykey, { exclusiveStartKey: lek }, function(err, result) { if (err) return cb(err); if (result.items.length) finalSet.push.apply(finalSet, result.items); if (result.lastEvaluatedKey) nextBatch(result.lastEvaluatedKey); else cb(null, finalSet); }); }; nextBatch(); }; getAll(primarykey, function(err, all) { console.log(err, all); }); 

几杯咖啡后,我写这个recursion函数..希望这可以帮助别人,如果你看到一个错误,请编辑它或留下评论

  var DynamoDbItemFetcher = function(table,hash,maxItems,callback){ var self = this; self.table = table; self.startKey = null; self.hash = hash; self.maxItems = maxItems; self.items = []; self.callback = callback; self.getItems = function(){ var params = {}; if(self.startKey){ params.exclusiveStartKey = self.startKey; } ddb.query(self.table,self.hash,params,function(err1,result){ if(err1) return self.callback(err1, null); if(result){ self.items = self.items.concat(result.items); if(result.lastEvaluatedKey && result.lastEvaluatedKey.hash){ if(self.maxItems && self.items.length > self.maxItems){ self.callback(null,self.items); }else { self.startKey = result.lastEvaluatedKey;//reset start key self.getItems(callback);//recursive call... } }else{ //no more items..return whatever is in store. self.callback(null,self.items); } } else{ self.callback(null, null); } }); }; }; 

这是一个使用promise的变体。 我需要获取表名列表,而不是从表中扫描项目,但类似的概念适用。

 function getTableNames(key, prevTableNames) { return new Promise(function(resolve, reject) { let request = dynamodb.listTables({ ExclusiveStartTableName: key }, function(err, response) { if (err) { reject(err); } else { let tableNames = (prevTableNames || []).concat(response.TableNames); if (response.LastEvaluatedTableName) { getTableNames(response.LastEvaluatedTableName, tableNames) .then(resolve) .catch(reject); } else { resolve(tableNames) } } }); }); }