Javascript 使用云代码在解析服务器上同时更新和保存数千个对象。代码不';不适用于2个以上的对象。(Parse.Object.saveAll())

Javascript 使用云代码在解析服务器上同时更新和保存数千个对象。代码不';不适用于2个以上的对象。(Parse.Object.saveAll()),javascript,node.js,heroku,parse-server,parse-cloud-code,Javascript,Node.js,Heroku,Parse Server,Parse Cloud Code,在我的解析服务器中,我有一个名为Stats的类,其中包含列secondsPlayed(number)和timeScore(number) 我正在使用云代码更新列timeScore 以下代码仅在更新和保存1或2个对象时有效results.length。如果Parse.Query返回2个以上的结果,代码就会崩溃,我会得到以下错误 error: Failed running cloud function timeScore for user undefined with: Input: {} Erro

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

我正在使用云代码更新列
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)出现第五个也是最后一个错误。此错误不会以任何方式影响流程。所有250k对象都将更新和保存,而与batchSize无关

我想可能是因为我从未调用过
results.error
results.success
服务器认为我仍在做一些工作,并显示了错误。然而,我更新了我的代码如下,我仍然得到超时错误

此外,在每次超时错误之后,将再次从数据库调用processBatch()。因为我有5个超时错误,所以processBatch()被调用了5次。因此,在第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);
    });

});

要处理大于最大查询限制的对象数,请构建一个更抽象的函数,该函数使用查询的
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);
可以这样称呼:

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);
编辑在云函数的上下文中,如下调用它

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

代码看起来不错。有时解析错误不是很有指导意义。一种猜测是,Stats(或通过关系与Stats相关的对象)有一个ACL,该ACL需要许可用户。这里有一个调试步骤:不要在“Stats”上运行此代码。创建一个没有访问控制的全新类。给出一个单独的属性,一个在代码中递增1的整数值。它仍然中断吗?顺便提一下,代码中有一个问题会阻止它在数千个对象上运行:查询的最大限制是1000。我可以告诉你,一旦更基本的问题得到解决,如何解决这个问题。嗨,ACL是统计数据和每个统计数据对象的公共读写。我认为问题不在于读写权限,因为当我设置查询以便只返回2个对象时,代码确实起作用。当返回3个或更多对象时,我得到错误。解决方案是否与承诺有关?不。你的承诺代码看起来完美无缺。Stats对象是否与其他对象有任何关系?这就是我以前看到的神秘错误:stats对象的保存成功,但相关对象的保存失败(parse隐式保存保存对象的关系)。我的建议是,通过在一个全新的类上尝试这段代码,消除对数据模型/权限/或数据中其他错误的任何疑问,该类除了一个递增的int属性外,没有任何关系(没有任何类型的属性)。您好,我按照您的建议做了。尝试在具有新列的新类上运行代码,我的代码运行正常。你是对的。我意识到问题在于我导入mongodb的数据格式与解析不兼容。一旦我修复了我的代码工作。现在剩下的唯一问题是查询限制。从我的代码中可以返回的最大对象数是100,甚至是1000。如何取消查询限制,以便在数千个对象上运行代码?您好,我尝试了您的代码。你能检查一下我上面发布的代码作为更新,并告诉我为什么它不能正常工作吗?我的代码每次只更新和保存4204个对象,并在运行期间给出错误“heroku[router]:at=error code=H12 desc=“Request timeout”method=POST path=“/parse/functions/timeScore”5次。始终在同一个位置。我在代码中指出了console.log发生此错误的时间。此错误在日志和setTimeScore上出现5次()仅运行5次。第5次之后,代码停止运行,没有更新所有250000个对象。看起来是超时,不是代码问题。这是作为web请求或计划作业运行的。web请求内置超时。另一种可能是heroku施加资源限制。一种测试是尝试不同的batch大小。它会在100次时运行约42次吗?或者在10次时运行约420次吗?这并不准确,因为不同批次大小的开销不同,但了解这种行为是否在大约42次批次中发生,并且重复发生,这将是非常有用的。@MuratKaya-我不想成为这方面的一个害虫,但我在等着你意识到设计是不明智的这是一个可以访问成千上万条记录的系统,每一条记录都会根据挂钟时间进行更新。你在这里没有违反任何物理定律,但你正在违反经济定律。嗨,我知道你的意思,也理解你的观点。我只是想