使用云代码在 Parse Server 上一次更新和保存数千个对象。代码不适用于超过 2 个对象。(Parse.Object.saveAll())



在我的解析服务器中,我有一个名为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次。第 5 次后我再也得不到它了。我在该过程开始大约 2.5 分钟(30 秒*5(时收到第 5 个也是最后一个错误。此错误不会以任何方式影响该过程。无论批次大小如何,所有 250k 对象都将更新并保存。

我想可能是因为我从不打电话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) : {};
});
}

这说,获取一个由query指定的batchSize长一批对象,然后对检索到的对象执行某些操作,然后,如果可能有更多,请再次执行相同的操作,跳过我们已经处理过的对象。

您的流程步骤如下所示:

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

最新更新