我正在尝试对我的一些Parse数据运行一些统计数据,以便了解到目前为止的使用统计信息。
基本上我是基于创建它们的日期对属性进行排序,并尝试遍历每个属性以查看创建它的用户是否是该区域的新用户,以及它们是否是可结算用户(已输入付款信息的人)。用户可以是多个邮政编码的客户,并且可以在创建帐户后随时成为新邮政编码的客户,这使我收集此数据的方式变得复杂。对不起凌乱的代码,我试着添加一些评论以显示正在发生的事情。搜索“// 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);
});
});
对不起它太长而且很乱,如果你认为我应该更新这个没有大部分无法达到的代码,请告诉我。我只记得阅读一些关于promises的文档,说明当你在返回promise时调用promise的函数时,它们会有不同的行为。我认为返回一个promise的内部函数必须先完成,所以我会在这里受到保护,但显然我错了,因为我的提取永远不会被调用。
我感谢任何帮助!我已经被困在这几个小时了。
编辑 - 我已将代码更改为仅使用promises,而不是混合使用回调和承诺。事实证明我不需要再次获取属性,因为查询已经获取它。我必须有一个拼写错误的变量名称,或之前给我一个空对象的东西。
但是,现在我的问题是没有提取用户。它基本上和以前一样,只是在一个不同的地方,因为我实际上不需要做原始的提取。这是我更新的代码:
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);
});
});
答案 0 :(得分:1)
不要将promises与回调混合,选择2种方法中的1种并坚持使用。混合和匹配通常意味着某些内容会被删除,并且您的函数会在不调用status
处理程序的情况下提前退出。
使用promises将帮助您破解代码,以便更容易理解。
在运行fetch
之后,您不需要运行find
,因为查询应返回每个对象的所有列值。
以后使用时,您可能需要考虑使用.each
代替.find
。
使用promises时,你需要链接它们并返回嵌套的promises:
query.find().then(function(x) {
... // basic logic
return object.save(); // return when creating a promise
}).then( function(y) {
...
}) ...
注意,您可以链接save
,但需要返回承诺链的“头部”。