Parseで複数のqueryをまとめて実行する方法


parseのcloud codeで大量のqueryを実行する方法を調べたのでメモしておきます。

まず大前提としてParseの仕様的な制限をふまえておく必要があります。

- 一度のqueryで1000 Objectまでしか扱えない

- Cloud Functionは15秒でtime out(beforeSave/afterSaveは3秒)

参考 : [Cloud Code: limitation and API calls count](https://www.parse.com/questions/cloud-code-limitation-and-api-calls-count)

参考にした情報が古いものなので今は仕様変わっているかもしれません。

感覚的には5秒くらいでtime outになっている気もしなくはないです。。



ここでは、あるテーブルから大量のデータを取り出して別のテーブルへsaveするというサンプルコードで試してみます。

##Parse.Promise.whenを使う方法
promiseをarrayに入れてParse.Promise.whenに渡す方法です。
Parse.Promise.whenはPromise.allのように配列で渡されたpromiseの処理が全て終了するまでそこで止まります。

[追記]
そもそも無料プランだと秒間30リクエストまでという制限がありました。
Parse.Promise.when(queries)だと簡単に超えてしまいますね。
limit overしてるよという通知メールが来ましたが、30リクエスト以上でも何回か実行はできていました。
一瞬overしたくらいは大目に見てくれるんですかね。

```js:

Parse.Cloud.define("ParseQuerySaveTest2", function(request, response) {
  var query = new Parse.Query('MuchDataInTable');
  query.limit(1000);
  //query.skip();
  query.find()
  .then(function(results) {
    var queries = [];

    results.forEach(function(result){
      queries.push(createObject2(result));
    });
  
    return return Parse.Promise.when(queries);
  })
  .then(function(result) {
    response.success("ok!");
  })
  .fail(function(error) {
    response.error(error);
  });

});

function createObject2(result) {
  var content = result.get("content");
  
  var strage = new (Parse.Object.extend("Strage"));
  strage.set('content', content);
    
  return strage.save();
}
```

##Parse.Object.saveAllを使う方法
変更済みParse objectの配列をParse.Object.saveAllに渡す方法です。
Parse.Object.saveAllはParse objectの配列を渡すとまとめてsaveを実行してくれます。

```js:

Parse.Cloud.define("ParseQuerySaveTest1", function(request, response) {
  var query = new Parse.Query('MuchDataInTable');
  query.limit(1000);
  //query.skip();
  query.find()
  .then(function(results) {
    var queries = [];

    results.forEach(function(result){
      queries.push(createObject1(result));
    });
  
    return Parse.Object.saveAll(queries);
  })
  .then(function(result) {
    response.success("ok!");
  })
  .fail(function(error) {
    response.error(error);
  });

});

function createObject1(result) {
  var content = result.get("content");
  
  var strage = new (Parse.Object.extend("Strage"));
  strage.set('content', content);
    
  return strage;
}
```

##どちらを使うべき？

どちらも同じように機能するので両方とも試してみました。

Parse.Promise.whenを使った場合だと500件くらいでtimed outになってしまうことが多かったです。

Parse.Object.saveAllは1000件でも問題ありませんでした。

というわけでParse.Object.saveAllを使うことにしました。

##なかの人もsaveAllを推奨

他にもどちらを使うべきか悩んでいる人がいないか調べてみたらありました。

そのQ&Aでなかの人が以下のように返答しています。

saveAllを使いましょうとのことです。

> You should use saveAll. If you use Promises in the way shown, you will be creating a large number of network connections all at once, which can consume too many resources at one time. This would be especially problematic in Cloud Code. In the near future, we hope to update saveAll to use batches, so that it will send many objects in each network request, which will make it faster than separate requests in many situations.

[Parse.Object.saveAll vs Parse.Promise.when](https://www.parse.com/questions/parseobjectsaveall-vs-parsepromisewhen)


##1000件以上のobjectを一度に扱いたい場合は？

query.limitとquery.skipを組み合わせて頑張れば可能です。

詳しくはググると色々出てくると思います。。