在 Laravel Eloquent 中从数据透视表获取计数

8

我有一个订单和产品之间的多对多关系。

<?php
class Order extends Eloquent {

    public function user()
    {
        return $this->belongsTo('User');
    }

    public function products()
    {
        return $this->belongsToMany('Product');
    }
 }
 ?>


<?php
class Product extends Eloquent {

    public function orders()
    {
        return $this->belongsToMany('Order');
    }

 }
?>

需要获取每个产品被订购的次数。在mysql中,可以使用以下查询来完成此任务

SELECT products.id, products.description, count( products.id )
FROM products
INNER JOIN order_product ON products.id = order_product.product_id
INNER JOIN orders ON orders.id = order_product.order_id
GROUP BY product_id
LIMIT 0 , 30

以上查询的结果如下:

id  description   count(products.id)    
 1     Shoes          3
 2     Bag            2
 3     Sun glasses    2
 4     Shirt          2

如何使用laravel eloquent(不使用查询构建器)来完成此任务? 如何使用laravel eloquent获取每个产品的订单次数?

4个回答

31

对于未来的观众,截至Laravel 5.2,有原生功能可用于计算关系而无需加载它们,也无需涉及资源模型或访问器 -

针对批准答案中的示例,您需要将以下内容放置在控制器中:

$products = Product::withCount('orders')->get();

现在,当您在视图中迭代$products时,每个检索到的产品记录都有一个orders_count(或者通俗地说,只是一个{resource}_count)列,您可以像显示其他列值一样简单地显示它:

@foreach($products as $product)
    {{ $product->orders_count }} 
@endforeach

这种方法产生的数据库查询比已批准的方法少2个,而且唯一涉及到的模型是确保你的关系设置正确。如果你正在使用L5.2+,那么我建议使用这个解决方案。


1
如果可以的话,我会给你+10分。这应该是被接受的答案。 - ElChupacabra
不,它对于OP的版本不起作用。@ElChupacabra - kJamesy

21

请注意,Eloquent 在幕后使用 Query\Builder,因此在 Laravel 中没有像“不使用查询构建器查询 Eloquent”这样的东西。

而这就是你所需要的:

// additional helper relation for the count
public function ordersCount()
{
    return $this->belongsToMany('Order')
        ->selectRaw('count(orders.id) as aggregate')
        ->groupBy('pivot_product_id');
}

// accessor for easier fetching the count
public function getOrdersCountAttribute()
{
    if ( ! array_key_exists('ordersCount', $this->relations)) $this->load('ordersCount');

    $related = $this->getRelation('ordersCount')->first();

    return ($related) ? $related->aggregate : 0;
}

这将让您充分利用渴望加载(eager loading)的优势:
$products = Product::with('ordersCount')->get();

// then for each product you can call it like this
$products->first()->ordersCount; // thanks to the accessor

阅读有关Eloquent访问器和修改器的更多信息,

以及关于动态属性的信息,以上述访问器模拟的行为为例。


当然,您可以使用简单的连接来获得与您示例中完全相同的查询。


代码运行良好,我现在得到了期望的结果。谢谢你的帮助:)但还有一个问题。当访问ordersCount()时,函数getOrdersCountAttribute()是否会自动调用?你能解释一下这两个函数如何流程吗? - developer34
检查编辑 - 添加了文档链接,您可以在其中找到所需的所有内容。基本上,访问器/修改器利用魔术__get/__set,让您操作模型的属性,使其符合您的需求。created_at和其他时间戳的工作方式基本相同。 - Jarek Tkaczyk
我完全忘记了访问器/修改器。谢谢提醒!!! :):) - developer34

4
如果您已经拥有$products对象,您可以执行以下操作:
$rolecount = $products->roles()->count();

如果您正在使用贪婪加载:

$rolecount = $products->roles->count();

干杯。


0

我正在使用Laravel 5.1,通过这种方式我能够实现它

 $photo->posts->count()

而照片模型中的帖子方法看起来像这样

public function posts(){
    return $this->belongsToMany('App\Models\Posts\Post', 'post_photos');
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接