Skip to content

Instantly share code, notes, and snippets.

@rebolyte
Created February 22, 2017 15:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rebolyte/d69c8bc694eb9fb7d94e8acdaf3c878c to your computer and use it in GitHub Desktop.
Save rebolyte/d69c8bc694eb9fb7d94e8acdaf3c878c to your computer and use it in GitHub Desktop.
wrapper to get a list of items from DynamoDB
function getItems(opts) {
passMuster(opts, {
table: 'string',
hashkey: 'string',
items: 'array',
_optional: {
rangekey: 'string',
rangeval: 'string',
project: 'string'
}
});
// Check that they're all truthy to avoid the `typeof null === object`
// problem when we check the type below.
var allTruthy = opts.items.every(function (item) {
return !!item;
});
// Check based on the first item in the array passed in
var allSameType = opts.items.every(function (item, idx, arr) {
return typeof item === typeof arr[0];
});
if (!allTruthy) {
throw new Error('getItems: All objects or hashvals passed in must be truthy.');
}
if (!allSameType) {
throw new Error('getItems: All objects or hashvals passed in must be same type.');
}
return new Promise(function (resolve, reject) {
// let params = {
// RequestItems: {
// users: { <-- table name
// Keys: [
// {
// HashKey: 'hashkey'
// },
// ]
// },
// }
// Make a copy of the array passed in so we don't alter it.
// Shouldn't be necessary since primitives are passed by value,
// but hey, let's be safe.
var arr = opts.items.slice();
var arrOut = [];
// A callback that repeatedly calls batchWrite until all of the gets have completed
function callback(err, data) {
if (err) {
reject(err);
} else {
// console.log(data.ConsumedCapacity);
// Save the stuff we got back to our array of results
arrOut = arrOut.concat(data.Responses[opts.table]);
if ('UnprocessedKeys' in data && opts.table in data.UnprocessedKeys) {
// More data. Call again with the unprocessed items.
var retryParams = {
RequestItems: data.UnprocessedKeys
};
// console.log('Calling BatchGet again to retry ' + params.RequestItems[opts.table].length + ' UnprocessedKeys');
docClient.batchGet(retryParams, callback);
} else {
if (arr.length > 0) {
// console.log('BatchGet processed all items in the batch - going on');
// Start another round
doBatchGet();
} else {
// console.log('BatchGet processed all items in the batch - done');
resolve(arrOut);
}
}
}
}
function doBatchGet() {
var params = {
RequestItems: {},
ReturnConsumedCapacity: 'TOTAL'
};
params.RequestItems[opts.table] = {
Keys: []
};
if (opts.project) {
params.RequestItems[opts.table].ProjectionExpression = opts.project;
}
// console.log(arr);
for (var i = params.RequestItems[opts.table].Keys.length; i < 100; i++) {
// Nothing else to add to the batch if the input list is empty
if (arr.length === 0) {
break;
}
var curHash = arr.pop();
var curItem = {};
if (opts.rangekey) {
// Doing it this way, we can just pass in whole items
// to the function and extract the hash or hash+range info.
curItem[opts.hashkey] = curHash[opts.hashkey];
curItem[opts.rangekey] = curHash[opts.rangekey];
} else {
curItem[opts.hashkey] = (typeof curHash === 'object') ? curHash[opts.hashkey] : curHash;
}
params.RequestItems[opts.table].Keys.push(curItem);
}
// console.log('Calling BatchGet on ' + opts.table + ' with a new batch of ' + params.RequestItems[opts.table].Keys.length + ' items');
// console.log(params.RequestItems[opts.table].Keys[params.RequestItems[opts.table].Keys.length - 1]);
docClient.batchGet(params, callback);
}
// Kick off the first run
doBatchGet();
});
}
// Usage:
// getItems({
// table: 'users',
// hashkey: 'username',
// items: ['1', '2', '3']
// });
// or
// getItems({
// table: 'userTask',
// hashkey: 'username',
// rangekey: 'taskId',
// items: [
// { username: '1', taskId: '1', otherAttr: 'foo' },
// { username: '1', taskId: '2', otherAttr: 'foo' },
// { username: '1', taskId: '3', otherAttr: 'foo' }
// ]
// });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment