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