[CakePHP]counterCacheがすごく便利なのでメモ

例えば以下の2テーブルがあったとして・・・

ユーザの情報をもつユーザテーブル
users(Userモデル)

ユーザーがページを開くたびに保存されるログ(apacheのアクセスログみたいなものだと思ってもらえば)
もちろんuser_idというフィールドを持っている
user_logs(UserLogモデル)

このとき、User.idごとのページビュー(UserLogのレコード数)を取得したい場合はどうしますか?

僕の場合はコントローラで、


$bind = array(
    "hasMany" => array(
        "UserLog" => array(
            "fields" => array("count(id) as pv"),
            "conditions" => array("1 = 1 group by UserLog.id")
        )
    )
);
$this->User->bindModel($bind);

こんな感じで、取得していました。*1

でも、面倒だし、出力されるデータも

↓users = array(
    "User" => // 省略
    "UserLog" => array(
        "0" => array(
            // 省略
            "UserLog" => array(
                "0" => array(
                    "click" => // ここでやっとクリック数
                )
            )
        )
    )
);

すごく深くなってしまう。むだですよね。

counterCacheを使うと

usersテーブルに「user_log_count」*2 というフィールを追加。

UserLogモデルにbelongsToアソシエーションを追加して、counterCacheをtrueに

var $belongsTo = array(
    "User" => array(
        "counterCache" => true,
    ),
);

そうすると・・・

なんということでしょう!
UserLogにデータが追加されるたびにUser.user_log_countの数字がインクリメントされ、カウントが反映されます。
これでもうカウントを取得するためにUserLogをバインドする必要も無く、User単独でカウントが取得できるというわけ。

すごく便利でしょ!?

ちなみに
UserLogのレコードをdeleteしたらどうなるか?
UserLog.user_idを別のuser_idにupdateしたらどうなるか?
こういったことは検証していないので、もしやってみた方は教えていただけると嬉しいです。

  1. UserLogをベースに、group by user_idで取得することもできますよね。 検証はしてませんが、なんとなく重くなりそうな気がするので僕はUserモデルをベースにしてます。 []
  2. user_logsじゃないので注意!複数形じゃなく単数形で”user_log”_countね []
スポンサーリンク
336x280_1
336x280_1

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

スポンサーリンク
336x280_1

コメント

  1. designarea より:

    この記事のおかげでモデルにSQL文書いたりして処理していたものがだいぶ省略できました。参考になる記事ありがとうございました