You are here
Home > !Laravel > Eloquentでカウントするときの注意

Eloquentでカウントするときの注意

Eloquentのcount()の関数を使用して、DBのレコード数を数える作業はよく起こります。

例えば、前回の画像の件では、商品productのレコード1に対して商品画像product_imageレコードがが複数あるという、1対多の関係。そこでは、商品を削除するときに商品画像がないかをチェックする必要あります。画像のレコードがあるなら、削除を拒否あるいはユーザーに削除してよいか尋ねるということになります。

この場合は、商品画像があるかないかは、count()するのが一番。しかし、Eloquentではいろいろなカウントのコードの仕方があります。

今回は、これを説明するために、コントローラに特別にメソッドを作成してみました。

namespace App\Http\Controllers\User;

use App\Http\Controllers\Controller;
use App\Product;
use App\ProductImage;

class ProductController extends Controller
{
	public function getCount(Product $product)
	{
		$count1 = ProductImage::where('product_id', $product->product_id)->get()->count();
		$count2 = ProductImage::where('product_id', $product->product_id)->count();
		$count3 = $product->product_images->count();
		$count4 = $product->product_images()->count();

		return sprintf("<pre>count1 = %d\ncount2 = %d\ncount3 = %d\ncount4 = %d\n</pre>", $count1, $count2, $count3, $count4);
	}
}

最初の、$count1は、whereでproduct_imageのレコードを絞ってgetして、それらのレコードをcount()します。しかし、getしたのはIlluminate\Database\Eloquent\Collectionのオブジェクトであり、取得したレコードのデータすべてが入っています。2,3のレコード数なら問題ないけれど、1000とかあれば、それだけのデータがメモリーに入るわけで、単にレコード数が必要なのにとんでもない浪費です。

それに比べて次の、$count2は、SQLクエリのCOUNT(*)を使用するので、取得するのは、まさに1つのカウント数だです。$count1とは大きな違いです。

さて、Productのモデルには、

namespace App;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
...
    public function product_images()
    {
        return $this->hasMany('App\ProductImage');
    }
}

ProductImageとのリレーションが定義されています。

これを利用したのが、先の$count3です。コードすっきりしましたね。しかし、ここ注意してください。この取得のしかたは、先の$count1とまったく同じなのです。つまり、必要なレコードをすべて含んだCollectionを作成してから、それをカウント。

これを正しくクエリで実行してもらうのが、$count4です。ちょっとした違いですね。product_images->count()product_images()->count()か。

実際、これらの実行がどうなっているかは、実行したクエリを見ればわかります。以下は、Debugbarの結果です。

count

カウント数は皆同じですが、2と4では、select count(*)ですが、1と3は、select *となっていますね。

Leave a Reply

Top