使用Node JS递归获取DynamoDB查询中的所有项

Recursive Fetch All Items In DynamoDB Query using Node JS

本文关键字:查询 DynamoDB Node JS 递归 获取 使用      更新时间:2023-09-26

这可能更像是一个JS/Async问题,而不是DynamoDB特定的问题-

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

我正在使用一个NodeJS库,它是围绕AWS DynamoDB REST API的包装器。-Node-DynamoDB

DynamoDB对每个查询只返回1 MB的结果。为了获取结果提醒,它包含了lastEvaluatedKey。我们可以将其包含在另一个查询中,以获取另一个1mb的结果,等等…

我在写一个递归异步函数时遇到了困难,这个函数应该依次击中服务,直到我能得到所有的结果。(对于我的用例,表永远不会超过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);
});

喝了几杯咖啡后,我写了这个递归函数。希望这对其他人有所帮助,如果你看到一个错误,请编辑它或留下评论

    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);
                }
            });
        };
    };

下面是使用promises的一个变体。我需要获得一个表名列表,而不是从表中扫描项,但类似的概念也适用。

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)
        }
      }
    });
  });
}