168

I've been working on a shopping cart application and now I've come to the following issue..

There is a User, a Product and a Cart object.

  • The Cart table only contains the following columns: id, user_id, product_id and timestamps.
  • The UserModel hasMany Carts (because a user can store multiple products).
  • The CartModel belongsTo a User and CartModel hasMany Products.

Now to calculate the total products I can just call: Auth::user()->cart()->count().

My question is: How can I get the SUM() of prices (a column of product) of the products in cart by this User?
I would like to accomplish this with Eloquent and not by using a query (mainly because I believe it is a lot cleaner).

dazed-and-confused
  • 1,293
  • 2
  • 11
  • 19
Admiral
  • 1,878
  • 2
  • 12
  • 17

8 Answers8

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

The documentation is a little light for some of the Collection methods but all the query builder aggregates are seemingly available besides avg() that can be found at http://laravel.com/docs/queries#aggregates.

Salman Zafar
  • 3,844
  • 5
  • 20
  • 43
user1669496
  • 32,176
  • 9
  • 73
  • 65
  • wow thanks for that quick reply. It now just says there is no price column. It looks like eloquent is not looking at that Product table at all.... – Admiral Feb 10 '14 at 15:22
  • 5
    Actually that makes sense, you have to add the products table to the relationship, sorry. Try `$sum = Auth::user()->cart()->products()->sum('price');` or whatever the price column is on your products table. – user1669496 Feb 10 '14 at 16:13
  • Yeah I tried that already, but now it gives something like; "Call to undefined method Illuminate\Database\Query\Builder::product()" while I'm sure the cart model has a method product() with a hasMany method in it. – Admiral Feb 10 '14 at 16:31
  • 1
    I just tried to replicate the issue, and I think we are making this too hard. Your `Cart` model is really just the pivot table, so we shouldn't have to include that, as that's taken care of in the `User` and `Product` model with your relationship methods. `Auth::user()->products->sum('price');`. Also make sure you are logged in so the Auth class knows which user to grab. Your cart model probably shouldn't have the `products()` function, as that belongs in the `User` model for this relationship. You really shouldn't even need a model for `Cart`. – user1669496 Feb 10 '14 at 18:43
  • 1
    That worked for me! I stopped using the cartclasses. Both the User and the product now have a belongsToMany() method. Now I am able to use price: {{ Auth::user()->products->sum('price') }} Thanx, This case is solved. – Admiral Feb 10 '14 at 20:56
  • Okay, I updated my original answer to what worked for you. Thanks. – user1669496 Feb 10 '14 at 22:06
  • 14
    Something isn't quite right here - your link refers to applying aggregate functions to database queries, but `products->sum` implies it is call sum on a collection object, rather than on the builder object returned by products(). It's worth clarifying which one you mean here, and ideally provide a link to explain both. – Benubird Nov 05 '14 at 10:59
  • When doing this with a many-to-many relationship you can do something similar to `Auth::user()->products->sum('pivot.price')`. – DutGRIFF Aug 04 '15 at 12:50
  • How I can have both sum and avg both with a single command/query? – hpaknia Jan 04 '17 at 21:37
  • How would you make this into a function on the User class? Is that possible? – Jepzen Apr 30 '18 at 09:04
  • 1
    @user3158900 Is there a difference between `Auth::user()->products->sum('price')` and `Auth::user()->products()->sum('price')`? – user3253002 Jan 30 '19 at 15:04
  • 4
    @user3253002 using a relationship without parenthesis `...->products->...` will query the database to get all of the current model's related products and then work with that in-memory collection. Using `...->products()->...` just modifies the query being build without executing it until something like `->sum()` is called.The latter can be more efficient, as it avoids transferring unnecessary information from the database into memory. – Siegen Feb 19 '19 at 07:55
98

this is not your answer but is for those come here searching solution for another problem. I wanted to get sum of a column of related table conditionally. In my database Deals has many Activities I wanted to get the sum of the "amount_total" from Activities table where activities.deal_id = deal.id and activities.status = paid so i did this.

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

it returns

"paid_sum_count" => "320.00"

in Deals attribute.

This it now the sum which i wanted to get not the count.

ahmad ali
  • 1,155
  • 1
  • 9
  • 17
24

I tried doing something similar, which took me a lot of time before I could figure out the collect() function. So you can have something this way:

collect($items)->sum('amount');

This will give you the sum total of all the items.

Philip E
  • 838
  • 9
  • 15
  • 4
    the name of the function is actually `collect() ` – Leonardo Beal May 02 '17 at 15:15
  • you're probably better off just looping the array. `collect()` is used to enrich an array into a collection object, but if you dont have a collection in the first place it might be better to just use the raw array – Flame Aug 05 '18 at 17:51
17

you can do it using eloquent easily like this

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

its will return a sum of fields, if apply condition on it that is also simple

$sum = Model::where('status', 'paid')->sum('sum_field');
Ukesh
  • 53
  • 3
M Umer Yasin
  • 284
  • 3
  • 6
9

Since version 8, there is a withSum method on Eloquent, so you could use this.

Auth::user()->withSum('products', 'price')->products_sum_price;

This won't load all products into memory and then sum it up with collection method. Rather it will generate a sub query for the database, so it's quicker and uses less memory.

miken32
  • 42,008
  • 16
  • 111
  • 154
vstruhar
  • 185
  • 1
  • 3
  • 10
7

You can pass this as UserModel attribute. Add this code to UserModel.

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

I assume something like this:

  • UserModel has a one to many relationship with a CartModel named cart
  • CartModel has a one to many relationship with ProductModel named products

And then you can get sum price of the product like this:

Auth::user()->product_price
Cak Bud
  • 190
  • 2
  • 9
5

Also using query builder

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

To get summation of all rate value inside table rates.

To get summation of user products.

DB::table("users")->get()->sum("products")
Ahmed Mahmoud
  • 1,724
  • 1
  • 17
  • 21
4

For people who just want to quickly display the total sum of the values in a column to the blade view, you can do this:

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

You can also do it for averages:

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

Min:

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

Max:

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

To get the Count of a table:

{{ \App\Models\ModelNameHere::count() }}
Ray
  • 49
  • 1