解析后台作业查询迭代在获取数据之前返回

Parse background job query iterations are returning before fetching data

我正在尝试 运行 我的一些 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);
    });
});

很抱歉,它又长又乱,如果您认为我应该在没有大部分未达到的代码的情况下更新它,请告诉我。我只记得读过一些关于 promise 的文档,说当你在 returns 一个 promise 之后调用一个 promise 的函数时,它们有不同的行为。我认为 returns 承诺必须先完成的内部函数,所以我会在这里受到保护,但显然我错了,因为我的提取永远不会被调用。

感谢您的帮助!我已经坚持了几个小时了。

编辑 - 我已将代码更改为仅使用承诺,而不是回调和承诺的混合。事实证明我不需要再次获取 属性,因为查询已经获取了它。我一定是有一个拼写错误的变量名或者之前给了我一个空对象的东西。

但是,现在我的问题是没有获取用户。基本上和以前一样的问题,只是在不同的地方,因为我实际上不需要做原始的获取。这是我更新的代码:

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

不要将 promises 与回调混合使用,从 2 种方法中选择一种并坚持使用。混合和匹配通常意味着某些东西被丢弃并且您的函数提前退出而不调用 status 处理程序。

使用 promises 将帮助您分解代码,使其更易于理解。

您不需要 运行 fetch 在 运行 宁 find 之后,因为查询应该 return 每个列的所有列值对象。

为了将来使用,您可能需要考虑使用 .each 而不是 .find

使用 promise 时,您需要将它们和 return 嵌套的 promise 链接起来:

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

请注意,您可以链接 save,但您需要 return 承诺链的 'head'。