ParseのCloud Codeを使ってサーバーサイドのコードを記述し、ランダムなオブジェクトを取得する方法

Parseというサービスを用いると、クラウド上のデータベース機能が簡単に利用できます。
さらに、Cloud Codeを使えばJavaScriptでサーバーサイドの処理を記述することも可能です。

とても便利なParseですが、現在、残念ながらParseにはデータベース上からランダムなオブジェクトを返すAPIが無いようです。
そこで、Cloud Codeを用いてデータベース上のランダムなオブジェクトを取得する方法を実装してみましたので、その手順およびコードを解説してみたいと思います。
ランダムな相手とネットワーク対戦するゲームなどに応用可能かと思います。

Cloud Codeを使わずに、端末からデータベースの行の数をカウントするAPIを使う方法もあるのですが、スケーラブルではなく、通信の回数が増えてしまうのが問題です。
従って、Cloud Codeを用いて、一回の通信で済み、なおかつスケーラブルなコードを書くのがベストかと思います。

Cloud Codeに関して、基本的な使い方は公式サイトに従えば大丈夫かと思います。
https://www.parse.com/docs/jp/cloud_code_guide
以下は、上記の解説の”クラウド関数”までの内容を踏まえた上での解説になります。

まず、Parseのサイトにログイン後、新規アプリを作成します。
その後、Add Classによりクラス（テーブル）の追加を行います。
今回は2つのテーブルを追加します。
一つ目のテーブルは、データの登録数をカウントするためだけのものにします。
今回は、Customを選択しCountという名前で作成します。
そして、Number型のcountという名前の列を追加します。
そして、行を追加しcountの初期値を0にしておきます。
![スクリーンショット 2015-02-20 21.30.52.png](https://qiita-image-store.s3.amazonaws.com/0/35297/fe5c14a5-ca41-8903-ef3a-31daa05a1dc9.png)
このクラスには、行は一つしか配置しません。

次に、もう一つクラスを追加します。
Customを選択し、RandomNumbersという名前で作成してください。
続いて列を追加します。
Number型でindexNumberという名前の列と、Number型でrandomNumberという名前の列を追加します。
![スクリーンショット 2015-02-20 21.38.48.png](https://qiita-image-store.s3.amazonaws.com/0/35297/3ef94ec1-75f3-7158-b599-06c4c357a9f1.png)
まだ行を追加する必要はありません。

次に、JavaScriptで書いたCloud Codeをデプロイします。
デプロイの手順は上記のリンクに書かれていますので、ここでは省きます。
JavaScriptのコードは以下の通りです。

```js:main.js
Parse.Cloud.define("randomObject", function(request, response) {
  var count;
  var query = new Parse.Query("Count");
  query.limit = 1;
  query.find({
    success: function(results) {
      count = results[0].get("count");
      if(count <= 0){
        response.error("No records were found!");
      }
      var randNum = Math.floor((Math.random() * count)) + 1;
      var query = new Parse.Query("RandomNumbers");
      query.equalTo("indexNumber", randNum);
      query.limit = 1;
      query.find({
        success: function(results) {
          　response.success(results[0]);
        },
        error: function() {
          　response.error("Couldn't find the results.");
        }
      });  
    },
    error: function() {
      response.error("Failed!");
    }
  });
});


Parse.Cloud.beforeSave("RandomNumbers", function(request, response) {
  var query = new Parse.Query("Count");
  query.limit = 1;
  query.find({
    success: function(results) {
      results[0].increment("count", 1);
      results[0].save();
      request.object.set("indexNumber", results[0].get("count"));
      response.success();
    },
    error: function() {
     response.error("Failed saving!");
   }
 });
});
```
2つの関数があります。
randomObjectという名前の関数は、ランダムなオブジェクトを取得するために端末から呼び出す関数です。レスポンスとしてランダムな行のデータを返します。
beforeSave関数は、RandomNumbersという名前のクラス（テーブル）にデータを保存する直前に呼ばれる関数です。これはCloud Codeに最初から備わっている関数です。この関数内で、Countクラスに保存されてる数値を一つ増やして保存します。

端末側にもコードの記述が必要です。iOS、Xcodeの場合は以下のように書けます。

```objc:ViewController.m
-(IBAction)add:(id)sender{
    PFObject *todo = [PFObject objectWithClassName:@"RandomNumbers"];
    [todo.ACL setPublicReadAccess:YES];
   
    int rand = arc4random_uniform(1000);
    todo[@"randomNumber"] = @(rand);
    
    [todo saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
        if (!succeeded) {
            NSLog(@"%@", error.description);
        }else{
            NSLog(@"Success!");
        }
    }];
}

-(IBAction)show:(id)sender{
        [PFCloud callFunctionInBackground:@"randomObject"
                           withParameters:@{}
                                    block:^(PFObject *result, NSError *error) {
                                        if (!error) {
                                            int randNum = [result[@"randomNumber"] intValue];
                                            NSLog(@"%d", randNum);
                                        }else{
                                            NSLog(@"%@", error.description);
                                        }
                                    }];
}
```
addメソッドでランダムな値をクラウド上に保存し、showメソッドでオブジェクトをランダムに取得します。
アプリを実行し、addメソッドにひも付けられたボタンをタップすると、RandomNumbersクラスにデータの追加が行われます。
また、showメソッドにひも付けられたボタンをタップすると、RandomNumbersクラスから端末へオブジェクトとしてランダムにデータが渡されます。

このようにParseと端末が連携をとることで、サーバーサイドの開発の手間が大幅に省けるかと思います。アプリエンジニアは端末側の実装に集中できそうですね。