最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Recursive Fetch All Items In DynamoDB Query using Node JS - Stack Overflow

programmeradmin3浏览0评论

This is probably more of an JS/Async question than a DynamoDB specific question -

I want to fetch all the items in a table with a hash key in Amazon's DynamoDB. The table also has Range key in it.

I am using a NodeJS library which is a wrapper around AWS DynamoDB REST API. - Node-DynamoDB

DynamoDB only returns 1 MB worth of results with each query. To fetch reminder of results, it includes lastEvaluatedKey . We can include this in another query to fetch another 1 MB worth of results and so on...

I am facing difficulty in writing a recursive async function which should hit the service sequentially till i can get all the results back. (table will never have more than 10 MB for my use case, no chance of a runaway query)

Some pseudo code for illustration:

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

This is probably more of an JS/Async question than a DynamoDB specific question -

I want to fetch all the items in a table with a hash key in Amazon's DynamoDB. The table also has Range key in it.

I am using a NodeJS library which is a wrapper around AWS DynamoDB REST API. - Node-DynamoDB

DynamoDB only returns 1 MB worth of results with each query. To fetch reminder of results, it includes lastEvaluatedKey . We can include this in another query to fetch another 1 MB worth of results and so on...

I am facing difficulty in writing a recursive async function which should hit the service sequentially till i can get all the results back. (table will never have more than 10 MB for my use case, no chance of a runaway query)

Some pseudo code for illustration:

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.
    }
});
Share Improve this question edited Jan 18, 2017 at 11:42 Steven de Salas 21.5k9 gold badges77 silver badges84 bronze badges asked Aug 11, 2014 at 11:10 KoderKoder 1,9143 gold badges26 silver badges42 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 7
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);
});

After few cups of coffee, i wrote this recursive function.. Hope this helps others, If you see a bug , please edit it or leave a ment

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

Here's a variation using promises. I needed to get a list of table names, not scan items from a table, but similar concepts apply.

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)
        }
      }
    });
  });
}
发布评论

评论列表(0)

  1. 暂无评论