Laravel Eloquent关联模型中的列求和

168

我正在开发一个购物车应用程序,现在遇到以下问题:

有一个用户(User)、产品(Product)和购物车(Cart)对象。

  • 购物车表只包含以下列:id, user_id, product_id 和时间戳。
  • UserModelhasMany Carts(因为用户可以存储多个产品)。
  • CartModel belongsTo User 和 CartModelhasMany Products。

现在,我可以通过调用Auth::user()->cart()->count()来计算总产品数。

我的问题是:如何获取此用户购物车中产品价格(product表的一列)的SUM()
我希望使用Eloquent完成这个操作,而不是使用查询(主要是因为我认为它会更清晰明了)。

8个回答

319
Auth::user()->products->sum('price');

文档对于一些Collection方法来说有点简略,但除了可以在http://laravel.com/docs/queries#aggregates找到的avg()之外,所有查询构建器聚合都似乎可用。


5
实际上这是有道理的,你需要将商品表格添加到关系中,抱歉。尝试使用$sum = Auth ::user()->cart()->products()->sum('price'); 或者使用你在商品表格上的价格列。 - user1669496
1
我刚试图复制这个问题,我认为我们正在把它搞得太难了。你的“Cart”模型实际上只是一个中间表,所以我们不应该包括它,因为在“User”和“Product”模型中使用关系方法已经处理了这个问题。Auth::user()->products->sum('price');。还要确保您已登录,以便Auth类知道要获取哪个用户。您的购物车模型可能不应该有“products()”函数,因为这属于此关系的“User”模型。您甚至不需要一个“Cart”模型。 - user1669496
1
那对我有用!我停止使用cartclasses。现在用户和产品都有belongsToMany()方法。 现在我可以使用价格:{{Auth :: user()->products->sum('price')}} 谢谢,这个问题已经解决了。 - Admiral
14
这里似乎有些不对 - 你的链接涉及将聚合函数应用于数据库查询,但products->sum表明在集合对象上调用sum,而不是在products()返回的生成器对象上调用。值得澄清你指的是哪一个,并最好提供一个链接来解释两者。 - Benubird
4
使用不带括号的关系操作符...->products->...将会查询数据库以获取当前模型的所有相关产品,并在内存集合中处理。而使用...->products()->...则仅仅修改正在构建的查询,直到调用类似于->sum()这样的方法时才执行查询。后者可能更加高效,因为它避免了从数据库传输不必要的信息到内存中。 - Siegen
显示剩余7条评论

100

这不是您需要的答案,而是给那些正在寻找其他问题解决方案的人。 我想有条件地获取相关表格中一列的总和。 在我的数据库中,交易(Deals)有多个活动(Activities)。 我想要获取“Activities”表中“amount_total”的总和,其中activities.deal_id = deal.id且activities.status = paid 所以我做了这个。

$query->withCount([
'activity AS paid_sum' => function ($query) {
            $query->select(DB::raw("SUM(amount_total) as paidsum"))->where('status', 'paid');
        }
    ]);

它返回

"paid_sum_count" => "320.00"

在交易属性中。

现在这就是我想要得到的总数,而不是计数。


10
在许多情况下这是最好的,因为您可以按此进行排序而无需获取所有记录。 - Sabrina Leggett
它运行良好,但我们必须在上述解决方案中添加groupBy()方法。 - dipenparmar12
1
这必须是被接受的答案。 - ManojKiran A
今天有了 withSum。工作变得更加容易了。 - Gato de Schrödinger

24
我曾尝试类似的操作,花费了很多时间才弄清楚collect()函数。你可以这样做: collect($items)->sum('amount');
这会给你所有项目金额的总和。

4
函数的名称实际上是collect() - Leonardo Beal
你最好只是循环数组。collect()用于将数组转换为集合对象,但如果你一开始没有集合,最好只使用原始数组。 - Flame

17

你可以像这样轻松使用 Eloquent 来完成它

$sum = Model::sum('sum_field');

它将返回字段的总和,如果对其应用条件,那也很简单。

$sum = Model::where('status', 'paid')->sum('sum_field');

10
自从版本8以来,Eloquent上有一个withSum方法,您可以使用它。
Auth::user()->withSum('products', 'price')->products_sum_price;

这不会将所有产品加载到内存中,然后使用集合方法对其进行求和。相反,它将为数据库生成子查询,因此速度更快,使用的内存更少。


运行得非常好。可惜你不能使用这种方法为它命名个性化的名称 :s。 - MrEduar
是的,而且适用于 Laravel 10。 - Mel

7

您可以将此作为UserModel属性传递。 将此代码添加到UserModel中。

public function getProductPriceAttribute(){
    return $this->cart()->products()->sum('price');
}

我假设大概是这样的:
  • UserModel 与名为 cart 的 CartModel 存在一对多关系
  • CartModel 与名为 products 的 ProductModel 存在一对多关系

然后您可以像这样获取产品总价:

Auth::user()->product_price

2
感谢您在11年后指出这一点。我想现在我可以继续进行这个项目了 ;) - Admiral
@theAdmiral 很想见到来自2025年的时间旅行者。 - HosseyNJF

5

同时使用查询构建器

DB::table("rates")->get()->sum("rate_value")

获取表格费率内所有费率值的总和。

获取用户产品的总和。

DB::table("users")->get()->sum("products")

3

对于那些只想快速在Blade视图中显示一列值的总和的人,你可以这样做:

{{ \App\Models\ModelNameHere::sum('column_name') }}

您也可以用同样的方法来计算平均数

{{ \App\Models\ModelNameHere::avg('column_name') }}

Min:

{{ \App\Models\ModelNameHere::min('column_name') }}

Max:

{{ \App\Models\ModelNameHere::max('column_name') }}

获取表格的计数:
{{ \App\Models\ModelNameHere::count() }}

1
在 Blade 文件中使用模型外观是 Laravel 中一个不好的实践,不是吗? - pasindu
不太遵循MVC模式 - undefined

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