2015-05-30 64 views
0

我想對我的一些解析數據運行一些統計信息,以獲取到目前爲止的使用情況統計信息。解析後臺作業查詢迭代在獲取數據之前返回

基本上,我基於它們被創建的日期對屬性進行排序,並嘗試遍歷每個屬性以查看創建它的用戶是否是該區域的新用戶,以及它們是否是可結算用戶(已輸入付款信息的用戶)。用戶可以是多個郵政編碼的客戶,並且可以在創建帳戶後隨時成爲新郵政編碼的客戶,這使我必須收集這些數據變得更加複雜。對不起,代碼混亂,我試圖添加一些評論,以顯示發生了什麼事情。搜索「// HERE」以查看問題開始的位置。 (下面更新的代碼)

Parse.Cloud.job("runStatistics", function(request, status) 
{ 
    Parse.Cloud.useMasterKey(); 
    // These are variables I'm outputting to see the behaviour of this background job. fetchedProperties and 
    // fetchAttempts are both the same, and equal to the total number of properties, but the rest all remain 0. 
    var failedUsers = 0; 
    var successfulUsers = 0; 
    var skippedUsers = 0; 
    var nonSkippedUsers = 0; 
    var propertyFetchErrors = 0; 
    var fetchedProperties = 0; 
    var fetchAttempts = 0; 
    var totalProperties; 

    // These are associative arrays or arrays (key being the zip code) where I store whether or not someone 
    // is already a user for a zip code, or if they have requested a cut (purchasing from our app) 
    var usersForZIPCode = {}; 
    var cutsForZIPCode = {}; 

    //I create a statistics object for each zip code for each week 
    var Statistics = Parse.Object.extend("Statistics", 
    { 
     initialize: function(attrs, options) 
     { 
      this.newUsers = 0; 
      this.newBillableUsers = 0; 
      this.firstCut = 0; 
      this.additionalCuts = 0; 
      this.numCuts = 0; 
      this.totalBillableUsers = 0; 
     } 
    }); 
    var statisticsArray = new Array(); 
    var i = 0; 
    for(i = 0; i < serviceableZIPCodesArray.length; i++) //ServiceableZIPCodesArray is an array of the zip codes we currently service, defined elsewhere. 
    { 
     usersForZIPCode[ serviceableZIPCodesArray[i] ] = new Array(); 
     cutsForZIPCode[ serviceableZIPCodesArray[i] ] = new Array(); 
     var j = 1; 
     for(j = 1; j < 4; j++) 
     { 
      var statistics = new Statistics(); 
      statistics.set("zipCode", serviceableZIPCodesArray[i]); 
      statistics.set("week", j); 
      statisticsArray.push(statistics); 
     } 
    } 

    //Here I set up the property query. I have less than 1000 properties at the moment. 
    var propertyQuery = new Parse.Query("Property"); 
    propertyQuery.limit(1000); 
    propertyQuery.ascending("createdAt"); 
    propertyQuery.find( 
    { 
     success: function(results) 
     { 
      totalProperties = results.length; //This is properly set 
      for(var x = 0; x < results.length; x++) 
      { 
       var property = results[x]; 
       fetchAttempts++; //This is hit every time 
       property.fetch(//HERE 
       { 
        success: function(property) 
        { 
         fetchedProperties++; //This is never called, always returns 0. 
         dateCreated = property.createdAt; 
         var weekNum; 
         var newUserBool = false; 
         var billableUserBool = false; 
         var ZIPIndex = serviceableZIPCodesArray.indexOf(property.get("zip")); 
         if(serviceableZIPCodesArray.indexOf(property.get("zip")) == -1) 
         { 
          skippedUsers++; //this is never called, always returns 0 
         } 
         else 
         { 
          nonSkippedUsers++; //this is never called, always returns 0 

          //These look a bit messy. Basically I'm using the current property's zip code as a key to get an 
          //array of users that already have properties in that zip code, so I don't count them twice 
          if(usersForZIPCode[ property.get("zip") ].indexOf(property.get("User")) == -1) 
          { 
           usersForZIPCode[ property.get("zip") ].push(property.get("User")); 
           newUserBool = true; //If the index was -1, they are a new user. 
          } 
          property.get("User").fetch(//User is a pointer to a User object that owns this property 
          { 
           success: function(user) 
           { 
            successfulUsers++; //this is never called, always returns 0 
            if(user.has(/* removing this in case it's a security issue*/)) billableUserBool = true; 
            //This tells us which week the property was created: 1, 2, or 3. 
            if(dateCreated.getDate() < 18) weekNum = 1; 
            else if(dateCreated.getDate() < 25) weekNum = 2; 
            else weekNum = 3; 
            //Based on which week the object was created, we update the statistics object 
            switch(weekNum) 
            { 
             case 1: 
              if(newUserBool) 
              { 
               if(billableUserBool) 
               { 
                statisticsArray[ ZIPIndex*3 ].increment("newBillableUsers"); 
                statisticsArray[ ZIPIndex*3 ].increment("newUsers"); 
                statisticsArray[ ZIPIndex*3 ].increment("totalBillableUsers"); 
                statisticsArray[ ZIPIndex*3 + 1 ].increment("totalBillableUsers"); 
                statisticsArray[ ZIPIndex*3 + 2 ].increment("totalBillableUsers"); 
               } 
               else 
               { 
                statisticsArray[ ZIPIndex*3 ].increment("newUsers"); 
               } 
              } 
              break; 
             case 2: 
              if(newUserBool) 
              { 
               if(billableUserBool) 
               { 
                statisticsArray[ ZIPIndex*3 + 1 ].increment("newBillableUsers"); 
                statisticsArray[ ZIPIndex*3 + 1 ].increment("newUsers"); 
                statisticsArray[ ZIPIndex*3 + 1 ].increment("totalBillableUsers"); 
                statisticsArray[ ZIPIndex*3 + 2 ].increment("totalBillableUsers"); 
               } 
               else 
               { 
                statisticsArray[ ZIPIndex*3 + 1 ].increment("newUsers"); 
               } 
              } 
              break; 
             case 3: 
              if(newUserBool) 
              { 
               if(billableUserBool) 
               { 
                statisticsArray[ ZIPIndex*3 + 2 ].increment("newBillableUsers"); 
                statisticsArray[ ZIPIndex*3 + 2 ].increment("newUsers"); 
                statisticsArray[ ZIPIndex*3 + 2 ].increment("totalBillableUsers"); 
               } 
               else 
               { 
                statisticsArray[ ZIPIndex*3 + 2 ].increment("newUsers"); 
               } 
              } 
              break; 
             default: 
            } 

           }, 
           error: function(user, error) 
           { 
            failedUsers++; //this is never called, always returns 0 
           } 
          }).then(
          function() 
          { 
            successfulUsers++; 
          }, 
          function(error) 
          { 
            failedUsers++; //this is never called, always returns 0 
          }); 
         } 
        }, 
        error: function(property, error) 
        { 
         propertyFetchErrors++; //this is never called, always returns 0 
        } 
       }).then(
       function(property) 
       { 
        fetchedProperties++; //this is never called, always returns 0 
       }, 
       function(error) 
       { 
        propertyFetchErrors++; //this is never called, always returns 0 
       }); 
      } 
     }, 
     error: function(results, error) 
     { 
      status.error("Uh oh, something went wrong with the query" + error); 
     } 
    }).then(
     function() 
     { 
      console.log("failed users = " + failedUsers); 
      console.log("successful users = " + successfulUsers); 
      console.log("skipped users = " + skippedUsers); 
      console.log("nonSkipped users = " + nonSkippedUsers); 
      console.log("total properties = " + totalProperties); 
      console.log("fetch attempts = " + fetchAttempts); 
      console.log("property fetch errors = " + propertyFetchErrors); 
      console.log("fetched properties = " + fetchedProperties); 
      Parse.Object.saveAll(statisticsArray).then( 
      function() 
      { 
       status.success("created statistics objects"); 
      }, function(error) 
      { 
       status.error("Uh oh, something went wrong while saving." + error); 
      }); 
     }, 
     function(error) 
     { 
      status.error("something went wrong with the property query" + error); 
    }); 
}); 

我很抱歉它是如此的長,凌亂,如果你認爲我不應該說大部分沒有得到達到該代碼的更新這一點,讓我知道。我只記得閱讀關於承諾的一些文檔,說他們在返回承諾後調用承諾的功能時會有不同的行爲。我認爲返回承諾的內部函數必須先完成,所以我會在這裏受到保護,但顯然我錯了,因爲我的提取從未被調用。

我感謝任何幫助!我一直堅持這幾個小時。

編輯 - 我已將代碼更改爲僅使用承諾,而不是混合回調和承諾。事實證明,我不需要再次獲取屬性,因爲查詢已經獲取它。我必須有一個拼寫錯誤的變量名或之前給了我一個空對象的東西。

但是,現在我的問題是用戶沒有被抓取。它基本上和以前一樣,只是在不同的地方,因爲我實際上並不需要做原始的抓取。這裏是我更新的代碼:

Parse.Cloud.job("runStatistics", function(request, status) 
{ 
    Parse.Cloud.useMasterKey(); 
    // These are variables I'm outputting to see the behaviour of this background job. fetchedProperties and 
    // fetchAttempts are both the same, and equal to the total number of properties, but the rest all remain 0. 
    var failedUsers = 0; 
    var successfulUsers = 0; 
    var skippedUsers = 0; 
    var nonSkippedUsers = 0; 
    var propertyFetchErrors = 0; 
    var fetchedProperties = 0; 
    var fetchAttempts = 0; 
    var totalProperties; 

    // These are associative arrays or arrays (key being the zip code) where I store whether or not someone 
    // is already a user for a zip code, or if they have requested a cut (purchasing from our app) 
    var usersForZIPCode = {}; 
    var cutsForZIPCode = {}; 

    //I create a statistics object for each zip code for each week 
    var Statistics = Parse.Object.extend("Statistics", 
    { 
     initialize: function(attrs, options) 
     { 
      this.newUsers = 0; 
      this.newBillableUsers = 0; 
      this.firstCut = 0; 
      this.additionalCuts = 0; 
      this.numCuts = 0; 
      this.totalBillableUsers = 0; 
     } 
    }); 
    var statisticsArray = new Array(); 
    var i = 0; 
    for(i = 0; i < serviceableZIPCodesArray.length; i++) //ServiceableZIPCodesArray is an array of the zip codes we currently service, defined elsewhere. 
    { 
     usersForZIPCode[ serviceableZIPCodesArray[i] ] = new Array(); 
     cutsForZIPCode[ serviceableZIPCodesArray[i] ] = new Array(); 
     var j = 1; 
     for(j = 1; j < 4; j++) 
     { 
      var statistics = new Statistics(); 
      statistics.set("zipCode", serviceableZIPCodesArray[i]); 
      statistics.set("week", j); 
      statisticsArray.push(statistics); 
     } 
    } 

    //Here I set up the property query. I have less than 1000 properties at the moment. 
    var propertyQuery = new Parse.Query("Property"); 
    propertyQuery.limit(1000); 
    propertyQuery.ascending("createdAt"); 
    propertyQuery.find().then( 
     function(results) 
     { 
      totalProperties = results.length; //This is properly set 
      for(var x = 0; x < results.length; x++) 
      { 
       var property = results[x]; 
       fetchAttempts++; //This is hit every time 
         fetchedProperties++; //obviously, this now == fetchAttemps 
         dateCreated = property.createdAt; 
         var weekNum; 
         var newUserBool = false; 
         var billableUserBool = false; 
         var ZIPIndex = serviceableZIPCodesArray.indexOf(property.get("zip")); 
         if(serviceableZIPCodesArray.indexOf(property.get("zip")) == -1) 
         { 
          skippedUsers++; //this gets set. 
         } 
         else 
         { 
          nonSkippedUsers++; //this gets set 

          //These look a bit messy. Basically I'm using the current property's zip code as a key to get an 
          //array of users that already have properties in that zip code, so I don't count them twice 
          if(usersForZIPCode[ property.get("zip") ].indexOf(property.get("User")) == -1) 
          { 
           usersForZIPCode[ property.get("zip") ].push(property.get("User")); 
           newUserBool = true; //If the index was -1, they are a new user. 
          } 
          property.get("User").fetch().then(//User is a pointer to a User object that owns this property 
          function(user) 
          { 
            successfulUsers++; 
            if(user.has(/* removing this in case it's a security issue*/)) billableUserBool = true; 
            //This tells us which week the property was created: 1, 2, or 3. 
            if(dateCreated.getDate() < 18) weekNum = 1; 
            else if(dateCreated.getDate() < 25) weekNum = 2; 
            else weekNum = 3; 
            //Based on which week the object was created, we update the statistics object 
            switch(weekNum) 
            { 
             case 1: 
              if(newUserBool) 
              { 
               if(billableUserBool) 
               { 
                statisticsArray[ ZIPIndex*3 ].increment("newBillableUsers"); 
                statisticsArray[ ZIPIndex*3 ].increment("newUsers"); 
                statisticsArray[ ZIPIndex*3 ].increment("totalBillableUsers"); 
                statisticsArray[ ZIPIndex*3 + 1 ].increment("totalBillableUsers"); 
                statisticsArray[ ZIPIndex*3 + 2 ].increment("totalBillableUsers"); 
               } 
               else 
               { 
                statisticsArray[ ZIPIndex*3 ].increment("newUsers"); 
               } 
              } 
              break; 
             case 2: 
              if(newUserBool) 
              { 
               if(billableUserBool) 
               { 
                statisticsArray[ ZIPIndex*3 + 1 ].increment("newBillableUsers"); 
                statisticsArray[ ZIPIndex*3 + 1 ].increment("newUsers"); 
                statisticsArray[ ZIPIndex*3 + 1 ].increment("totalBillableUsers"); 
                statisticsArray[ ZIPIndex*3 + 2 ].increment("totalBillableUsers"); 
               } 
               else 
               { 
                statisticsArray[ ZIPIndex*3 + 1 ].increment("newUsers"); 
               } 
              } 
              break; 
             case 3: 
              if(newUserBool) 
              { 
               if(billableUserBool) 
               { 
                statisticsArray[ ZIPIndex*3 + 2 ].increment("newBillableUsers"); 
                statisticsArray[ ZIPIndex*3 + 2 ].increment("newUsers"); 
                statisticsArray[ ZIPIndex*3 + 2 ].increment("totalBillableUsers"); 
               } 
               else 
               { 
                statisticsArray[ ZIPIndex*3 + 2 ].increment("newUsers"); 
               } 
              } 
              break; 
             default: 
            } 
          }, 
          function(error) 
          { 
            failedUsers++; //this is never called, always returns 0 
          }); 
         } 
      } 
     }, 
     function(results, error) 
     { 
      status.error("Uh oh, something went wrong with the query" + error); 
     } 
    ).then(
     function() 
     { 
      console.log("failed users = " + failedUsers); 
      console.log("successful users = " + successfulUsers); 
      console.log("skipped users = " + skippedUsers); 
      console.log("nonSkipped users = " + nonSkippedUsers); 
      console.log("total properties = " + totalProperties); 
      console.log("fetch attempts = " + fetchAttempts); 
      console.log("property fetch errors = " + propertyFetchErrors); 
      console.log("fetched properties = " + fetchedProperties); 
      Parse.Object.saveAll(statisticsArray).then( 
      function() 
      { 
       status.success("created statistics objects"); 
      }, function(error) 
      { 
       status.error("Uh oh, something went wrong while saving." + error); 
      }); 
     }, 
     function(error) 
     { 
      status.error("something went wrong with the property query" + error); 
    }); 
}); 

回答

1

不要混淆承諾和回調,選擇2種方法中的1種並堅持下去。混合和匹配通常意味着某些東西會被丟棄,並且您的函數會提前退出而不調用status處理程序。

使用承諾將幫助您打破代碼,使其更易於遵循。

在運行find後,您不應該需要運行fetch,因爲查詢應返回每個對象的所有列值。

爲了將來的使用,您可能要考慮使用.each而不是.find

使用時你需要把它們連承諾並返回嵌套承諾:

query.find().then(function(x) { 
    ... // basic logic 
    return object.save(); // return when creating a promise 
}).then(function(y) { 
    ... 
}) ... 

注意,你可以在save鏈,但你需要返回的承諾鏈的「頭」。

+0

我想我對承諾的理解有點偏離。我認爲他們幫助確保在你繼續前完成所有事情。 我一開始沒有抓取,但遇到了一些空問題。也許這是一個單獨的問題,並且取回實際上並不是必需的。我會重寫我的代碼,而不是再次獲取,看看它是否有效,如果是,請將其標爲正確。 我最初使用每個,但有一個錯誤,說你不能在一個有序數組上使用每個。按創建日期排序對統計數據非常重要,因此在這種情況下使用find是必要的。 –

+0

我已更新我的代碼以使用承諾而不是回調。但是,我仍然遇到基本上同樣的問題,即我沒有通過獲取用戶的承諾獲得承諾。還有什麼想法?謝謝。 –

+1

我仍然看到你的代碼中的回調,並且承諾應該被鏈接在一起。如果你承諾承諾,你需要退還,以便外部的承諾有待等待。 – Wain