使用云代码一次在Parse Server上更新和保存数千个对象。代码对2个以上的对象无效。 (Parse.Object.saveAll())

时间:2018-06-22 15:47:23

标签: javascript node.js heroku parse-server cloud-code

在解析服务器中,我有一个名为Stats的类,其中包含列secondsPlayed(数字)和timeScore(数字)

我正在使用云代码更新timeScore列中的所有行

下面的代码仅在更新和保存1个或2个对象results.length时有效。如果Parse.Query返回的结果超过2,则代码崩溃,并且出现以下错误。

error: Failed running cloud function timeScore for user undefined with:
Input: {}
Error: {"code":101,"message":"Object not found."} functionName=timeScore, code=101, message=Object not found., , user=undefined
error: Error generating response. ParseError { code: 101, message: 'Object not found.' } code=101, message=Object not found.
error: Object not found. code=101, message=Object not found.

这是个问题,因为我需要更新和保存数千个对象。最好和最快的方法是什么?

为什么我的代码只能用于2个对象,但不能用于2个以上?我怎样才能解决这个问题?

这是我的代码

    var _ = require("underscore");

Parse.Cloud.define("timeScore", function(request, response) {

    var query = new Parse.Query("Stats");
    query.greaterThan("secondsPlayed", 1000);
    query.find().then(function(results) {

        _.each(results, function(result) {
            var secondsPlayed = result.get("secondsPlayed") || 0;
            result.set("timeScore", secondsPlayed*2);

        });
        return Parse.Object.saveAll(results);

    }).then(function(results) {

        response.success(results);
    }, function(error) {

        response.error(error);
    }); });

这就是我的称呼

#!/usr/bin/env node
var Parse = require("parse/node");
Parse.initialize("xx",   "xx");
Parse.serverURL = "http://randomapp.herokuapp.com/parse";
Parse.Cloud.run('timeScore');

更新:

下面是我的最新代码。一切正常,除了我没有明显原因而收到以下错误的事实。

heroku[router]: at=error code=H12 desc="Request timeout" method=POST path="/parse/functions/timeScore

无论选择什么batchSize,我都会收到超时错误,并且每30秒就会收到一次。我一共得到了5次。第五次以后,我不再明白了。我在处理大约2.5分钟(30秒* 5)时遇到了第五个也是最后一个错误。此错误不会以任何方式影响该过程。不论batchSize如何,所有250k对象都将更新和保存。

我想可能是因为我从未致电results.errorresults.success,服务器认为我仍在做一些工作并显示错误。但是,我按照以下方式更新了代码,但仍然收到超时错误。

还在每个超时错误之后,从开始处再次调用processBatch()。由于我收到5个超时错误,processBatch()被调用了5次。因此,在第五次超时错误之后,有5个processBatch()函数同时运行(我通过日志确认了这一点)。

是什么导致我收到的heroku超时错误?我该如何解决?

var _ = require("underscore");
Parse.Cloud.define("timeScore", function(request, response) {
var counter = 0;
function processBatch(query, batchSize, startingAt, process) {
    query.limit(batchSize);
    query.skip(startingAt);

    return query.find().then(results => {

        return process(results).then(() => results.length);
    }).then(length => {

        return (length === batchSize)? processBatch(query, batchSize, startingAt+length, process) : {};
    });
}

function setTimeScores(stats) {
        console.log("LENGTH " + stats.length);
    _.each(stats, stat => {

        counter ++;
        stat.set("timeScore", counter);

    });
    return Parse.Object.saveAll(stats);
}

var query = new Parse.Query("Stats");

processBatch(query, 2500, 0, setTimeScores).then(results => {
        response.success(results);
    }).catch(error => {
        response.error(error);
    });

});

1 个答案:

答案 0 :(得分:1)

要处理大于最大查询限制的对象数,请构建一个更抽象的函数,该函数使用查询的limit()skip()来游标数据:

function processBatch(query, batchSize, startingAt, process) {
    query.limit(batchSize);
    query.skip(startingAt);
    return query.find().then(results => {
        return process(results).then(() => results.length);
    }).then(length => {
        return (length === batchSize)? processBatch(query, batchSize, startingAt+length, process) : {};
    });
}

这表示,获取batchSize指定的query长对象,然后对检索到的对象进行处理,然后,如果可能更多,请再次执行相同的操作,跳过我们已经处理过的对象。

您的处理步骤如下:

function setTimeScores(stats) {
    _.each(stats, stat => {
        var secondsPlayed = stat.get("secondsPlayed") || 0;
        stat.set("timeScore", secondsPlayed*2);
    });
    return Parse.Object.saveAll(stats);
}

这样称呼它:

let query = new Parse.Query("Stats");
query.greaterThan("secondsPlayed", 1000);
processBatch(query, 100, 0, setTimeScores);

EDIT 在云功能的上下文中,这样称呼它...

Parse.Cloud.define("computeStats", function(request, response) {
    let query = new Parse.Query("Stats");
    query.greaterThan("secondsPlayed", 1000);
    processBatch(query, 100, 0, setTimeScores).then(results => {
        response.success(results);
    }).catch(error => {
        response.error(error);
    });
});