Laravel hasOne + group_by, get sum - laravel

I'm currently scratching my head with this one.
What I have.
$entries = Meta::whereIn('settlement_id', [1])->groupBy('client_id')->get();
Meta::model() has a hasOne relation with other tables, in my example with a Sport table. With one attribute in my array I can achieve what I want.
So in a loop I have my field available $entry->Sport->amount this works perfectly.
What I need.
$entries = Meta::whereIn('settlement_id', [1,2,3])->groupBy('client_id')->get();
Now when I expand my array with multiple id's, I expect that $entry->Sport->amount returns the sum of all id's. But it doesn't.
I can't figure out what i'm doing wrong.
All help is appreciated.

Your hasOne relation means that each Meta will have a separate Sport, so when you loop $entries each $entry->Sport will have the amount related to the current Meta, not a sum of all of them.
If you want to have the sum of Sport amount for specific Metas it might be easier to make a query from the Sport model, something like this (I don't know how your relations is setup so this is just an example):
Sport::whereIn('meta_id', [1,2,3])->sum('amount');

Thats correct, is there a way that I can achieve this? By changing hasOne to something else?
I don't want to query each specific related Meta table.
public function Sport()
{
return $this->hasOne('App\Sport', 'settlement_meta_id');
}
my database table Sport looks like this:
protected $fillable = [
'settlement_meta_id',
'bet',
'payout'
];

Related

Using Laravel Eloquent to count how many times something exists in an efficient manner

I have a table called rentals, within each row are columns state,city,zipcode which all house ids to another table with that info. There are about 3400 rentals. I am pulling each column to display the states,city and zipcode distinctly. I need to show how many rentals are in each one. I am doing this now via ajax, the person starts typing in what they want to see and it auto completes it with the count, but its slow because of the way im doing it.
$rentals_count = Rentals::where('published',1)->get();
foreach($states as $state) {
echo $state.”-“.$rentals_count->where(‘state’,$state->id)->count();
}
Above is roughly what im doing with pieces removed because they are not related to this question. Is there a better way to do this? It lags a bit so the auto complete seems broken to a new user.
Have you considered Eager loading your eloquent query? Eager loading is used to reduce query operations. When querying, you may specify which relationships should be eager loaded using the with method:
$rental_counts = Rentals::where('published',1)->with('your_relation')->get();
You can read more about that in Laravel Documentation
$rentals = Rentals::wherePublished(true)->withCount('state')->get();
When you loop through $rentals, the result will be in $rental->state_count
Setup a relation 'state' on rentals then call it like this
$rentals_count = Rentals::where('published',1)->with('state')->get()->groupBy('state');
$rentals_count->map(function($v, $k){
echo $v[0]->state->name .' - '. $v->count();
});
Meanwhile in Rentals Model
public function state(){
return $this->hasOne(State::class, 'state'); //state being your foreign key on rentals table. The primary key has to be id on your states table
}

How to combine three many to many relationship results in a single collection in Laravel?

I have a many to many relationship between the following:
actor <-> theater_play, actor <-> musical, actor <-> ballet_play
How can I make a single array to display all the results from these relationships in Laravel?
I have now:
$actor->theaterPlays, $actor->musicals, $actor->balletPlays
And I need to have something like this:
$actor->allPerformances
EDIT:
And I have to order theym by name, or by date of the performance etc.
Untested, however you should be able to create a new accessor within your Actor model which is responsible for merging all types together:
public function getAllPerformancesAttribute()
{
return $this->theaterPlays()
->get()
->merge($this->musicals()->get())
->merge($this->balletPlays()->get())
->all();
}

How to create a child by one SQL-request in Laravel?

If an author has many books ("one to many" relationship) and I want to create a child by $author_id I should do this:
$author = Author::find($author_id);
$author->books()->create([...]);
But this code produces two SQL-requests as well as this:
Author::find($author_id)->books()->create([...]);
To reduce the number of SQL-requests I should add author_id field into the $fillable array in my Book model and do this:
Book::create([
'author_id' => $author_id,
...
]);
Which approach is better? As for me, the first one looks more correct, more Eloquent way, but 2 SQL-requests are too much for such simple case. Are there any other ways to make only one SQL-request without touching the $fillable array?
The old school:
$book = new Book;
$book->author_id = $author_id;
//...
$book->save();
Or you could forceCreate, which bypasses fillable:
Book::forceCreate(['author_id' => $author_id, ...]);
As for which approach is better: if you know the author_id, then 2nd (without using the relationship). But from my experience, that's rarely the case, since you usually want to check whether the related model actually exists. But if you're confident in the correctness of your input, no need for 2 queries.

how to make relation between table and array of ids from another table laravel

i have 2 tables, stores and products
stores table has field called products_ids
in this case i am saving the products in the stores by their ids in products_ids field as an array like this [1,2,3,4,5] i know it's not good practice to do it like this but this is the situation.
how can i make a relation in the model to achieve thing like this
Store::with('products')->get();
thanks
I don't know if this would work for you, but try it anyway:
in your Store model add the following:
public function products ()
{
return Product::whereIn('id', $this->products_ids)->get();
}

How do I define relation between users and points in Eloquent ORM

I have 3 tables:
Users - for storing users
User_point - for associacion between users and points(has only user_id and point_id)
Points for description of points(id, amount, description)
How do I define a relation between these? I tried
public function points(){
return $this->belongsToMany('\App\Point', 'user_point');
}
but when I do
return $user->points()->sum('amount');
it returns just one
Edit:
At first I tried making it like this as it makes more sense:
public function points(){
return $this->hasMany('\App\Point');
}
But it wouldn't work
SUM is an aggregate function and so it should only return one row.
$user->points will be a collection of points attached to that user.
$user->points() is a query that you can do additional work against (i.e. $user->points()->whereSomething(true)->get()).
As user ceejayoz pointed out, using user->points() is going to return a builder which you can do additional work on. I believe using sum() on that will look at the first row returned which is what you indicated is actually happening.
Likely, what you really want to do is $user->points->sum('amount');
That will get the sum of that column for the entire collection.

Resources