Iterating over multiple parse.com classes (tables) and extracting queries

时间:2015-12-14 18:08:48

标签: javascript asynchronous parse-platform callback promise

Im betting this has something to do with asynchronicity of Javascript or something like that. I just read up about promises and thought it might solve my issue, but it hasnt yet. Anyhow, here is a code snippet and what Im aiming to achieve with it:

The scenario: I would like to query 10 tables and get the most recent posts(for sake of this example, 1 post) and store that in a dictionary of format

<Class Name> : <Obj Id>

The below code snippet does the following, or tries to do the following:

  1. Build an array called activeTables, that contains the list of tables to query. This array itself is stored on a separate table called Config
  2. For each item of the array activeTable, perform a query on that item, for the most recent item and add it to the dictionary

Seems straightforward but here's the result Im getting:

Assuming we run this on 3 tables called Table_1, Table_2, Table_3 and the most recent objs on each table are: recent_1, recent_2, recent_3 respectively, what I see on newlist is this:

newlist = {
   "Table_1" : ["recent_1", "recent_2", "recent_3"]
}

instead of :

newlist = {
    "Table_1" : ["recent_1"],
    "Table_2" : ["recent_2"],
    "Table_3" : ["recent_3"],
}

and it beats me, that while I was able to query the 3 tables and get the most recent post, only upon inserting it into the dictionary, it refuses to add a new key per table, once one key exists

(Also, am I using promises wrong? Since i still see the familiar pyramid of callback hell )

Code snippet referenced above:

Parse.Cloud.job("scanLists", function(request, status) {
  var activeTables = [];
  var getclass = Parse.Object.extend("Config");
  var query = new Parse.Query(getclass);
  query.equalTo("Name", "ActiveTablesConfigObj");
  query.find().then(function(activetables_obj) {
    var newlist = {};
    activeTables = activetables_obj[0].get("cObject").Active.slice();
    for (var i = 0; i < activeTables.length; i++) {
      var t_name = activeTables[i];          
      var get_atc = Parse.Object.extend(t_name);
      var query_newlist = new Parse.Query(get_atc);
      query_newlist.descending("createdAt");
      query_newlist.find().then(function (newlist_obj) {
        if (newlist.t_name === undefined) {
          newlist[t_name] = [newlist_obj[0].id];
        } else {
          newlist[t_name].push(newlist_obj[0].id);
        }
      });
    }
  });
});

2 个答案:

答案 0 :(得分:0)

解决!

答案是我必须使用匿名函数!

以下代码修复了问题

Parse.Cloud.job("scanLists", function(request, status) {
  var activeTables = [];
  var getclass = Parse.Object.extend("Config");
  var query = new Parse.Query(getclass);
  query.equalTo("Name", "ActiveTablesConfigObj");
  query.find().then(function(activetables_obj) {
    var newlist = {};
    activeTables = activetables_obj[0].get("cObject").Active.slice();
    for (var i = 0; i < activeTables.length; i++) {
      (function(i) {
        var t_name = activeTables[i];          
        var get_atc = Parse.Object.extend(t_name);
        var query_newlist = new Parse.Query(get_atc);
        query_newlist.descending("createdAt");
        query_newlist.find().then(function (newlist_obj) {
          if (newlist.t_name === undefined) {
            newlist[t_name] = [newlist_obj[0].id];
          } else {
            newlist[t_name].push(newlist_obj[0].id);
          }
        });
      })(i);
    }
  });
});

答案 1 :(得分:0)

我们可以通过几种方式改进代码。 (1)创建返回promises的较小函数,(2)当我们只需要一个结果时,使用query.first()而不是find()。为了说明这两点,这里有一个函数,它返回一个承诺,以获得第一个&#34; Config&#34;对象:

function getConfig() {
  var query = new Parse.Query("Config");
  query.equalTo("Name", "ActiveTablesConfigObj");
  return query.first();
}

看起来,稍后在代码中,您希望获得给定类的最新对象。继承人&#39;一个简洁的功能:

function newestInstanceOf(klass) {
    var query = new Parse.Query(klass);
    query.descending("createdAt");
    return query.first();
}

这里是棘手的部分(以及需要在解决方案中修复的部分)... query.first()和.find()异步运行。您的代码包含一个for循环,它生成几个只在函数返回后才能完成的promise。不确定你的实际代码是什么样的,但是这里是如何正确地完成它,在数组中收集promises,然后与Promise.when()一起执行它们:

_ = require("underscore");  // just a great util for arrays, providing things like map()

function scanLists() {
    var newlist = {};
    return getConfig().then(function(config) {
        var activeTables = config.get("cObject").Active;
        // build an array of promises to get the most recent object in each class
        var promises = _.map(activeTables, function(klass) {
            return newestInstanceOf(klass).then(function(newestInstance) {
                if (!newlist[klass]) { newlist[klass] = []; }
                newlist[klass].push(newestInstance.id);
            });
        });
        return Parse.Promise.when(promises);
   }).then(function() {
       return newlist;
   });
}

注意一切如何回报承诺?最后一件事......从云函数中调用它,包括调用响应成功/错误:

Parse.Cloud.job("scanLists", function(request, response) {
    scanLists().then(function(newlist) {
        // do something with newlist, if this involves a promise, then...
        return someObject.save();
    }).then(function(result) {
        response.success(result);
    }, function(error) {
        response.error(error);
    });
}