【问题标题】:Recursive Fetch All Items In DynamoDB Query using Node JS使用 Node JS 递归获取 DynamoDB 查询中的所有项目
【发布时间】:2014-08-11 11:10:58
【问题描述】:

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

我想在 Amazon 的 DynamoDB 中使用哈希键获取表中的所有项目。该表中还包含 Range 键。

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

DynamoDB 每次查询仅返回 1 MB 的结果。为了获取结果提醒,它包括 lastEvaluatedKey 。我们可以将其包含在另一个查询中,以获取另外 1 MB 的结果等等...

我在编写递归异步函数时遇到了困难,该函数应该按顺序访问服务,直到我可以取回所有结果。 (对于我的用例,表永远不会超过 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.
    }
});

【问题讨论】:

    标签: javascript node.js recursion amazon-web-services amazon-dynamodb


    【解决方案1】:
    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);
    });
    

    【讨论】:

    • 感谢您的回复。我写了一些与你的非常相似的东西,并且有一个额外的功能,可以选择限制结果数量...不确定现在接受哪个回复...
    • 又好又简单! golang sdk 有类似的东西叫做QueryPages
    【解决方案2】:

    喝了几杯咖啡后,我写了这个递归函数.. 希望这对其他人有帮助,如果您发现错误,请编辑或发表评论

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

    【讨论】:

    • 除了过度的“自我”之外,代码并没有严格限制结果的数量为 maxItems。可以通过在查询时向“params”对象添加“limit”参数来微调代码
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2020-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-07
      • 2012-11-23
      • 1970-01-01
      • 2020-01-31
      • 1970-01-01
      相关资源
      最近更新 更多