How to get the average of relation table? laravel - php

Is there an eloquent way to get the average from relation table? Here I have 2 tables.
I can get the average of all exams using withAvg, but I want also to get the average of each exam (see expected result). Can someone give an idea how to do it? thanks
Models:
Student (students)
- id
- name
Exam (exams)
- id
- title
- is_correct
- student_id
StudentExam (studentExams)
- id
- section
I have tried this one and its working fine.
StudentExam::whereSection(1)
->with('exams')
->withAvg('exams AS total_avg_exams', 'is_correct);
->first();
This results into:
{
section: 1,
total_avg_exams: 0.63,
exams: [{},{}],
}
expected result would be:
{
section: 1,
total_avg_exams: 0.63,
exams: [
{
avg_exams: 0.83,
...
},
{
avg_exams: 0.63,
...
}
]
}

You need to group the exams in the with statement. I will asume al the exams that are related share the same title so it should be something like this.
use Illuminate\Support\Facades\DB;
StudentExam::whereSection(1)
->with(['exams' => function($query){
//You need the title for grouping
//You will need the student id for the eager loading so relation works
//is_correct is needed for the query
return $query->select(
'title',
'student_id',
'is_correct',
DB::raw('avg(is_correct) as total_avg_exams'))
->groupBy('title');
}])
->withAvg('exams AS total_avg_exams', 'is_correct');
->first();

Related

Laravel. OrderBy query with last item hasMany relationship

need some help with a query on Laravel(PHP)
what I have :
Two tables. Expedients & ExpedientRevs with a hasMany relationship beetween them.
Expedient Model:
public function ExpedientRevs() {
return $this->hasMany('App\ExpedientRev');
}
What I need:
A list of the expedients (Distinct Expedient) order DESC by the last Expedients Revisions (last id of ExpedientRev)
I mean, if I have in ExpedientRev:
id expedient_id ..........
--- --------------
1 1
2 2
3 3
4 3
5 1
My result should be the expedients in this order : 1,3,2 (no duplicated expedients)
Any help will be appreciated
Thanks
Simplest way to do that;
$expedients = Expedient::orderByDesc(ExpedientRev::select('id')
->whereColumn('expedient_revs.expedient_id', 'expedients.id')
->latest()
->take(1)
)->get();
This will get the latest records by ExpedientRev model. If you want to include ExpedientRev in your results. You can use latestOfMany.
In your Expedients model add this one;
public function rev()
{
return $this->hasOne(ExpedientRev::class)->latestOfMany();
}
So you can use like this;
$expedients = Expedient::orderByDesc(ExpedientRev::select('id')
->whereColumn('expedient_revs.expedient_id', 'expedients.id')
->latest()
->take(1)
)->with('rev')->get();

Laravel 5.7 - Many To Many Relation - Select Movies which have the provided array of Genre IDs

This is my controller code:
if ($request->genre && !$request->search) {
$genres = explode(',', $request->genre);
return Movie::with('genres')->whereHas('genres', function ($q) use ($genres) {
return $q->whereIn('id', $genres);
})->paginate(10);
}
My pivot table contains movie_id and genre_id. Both movies and genres tables do not contain reference of ID of each other.
I would need to select all movies from the table which have genres selected by the user.
For example, an array of id's = [1, 4, 9] and to select from pivot table movies that contain those genre ids.
Thanks in advance!
EDIT:
General problem was return inside callback and the way I handled data later on. Thanks for your answers, I appreciate it! :)
You did a wrong query, try the given query.
return Movie::with(['genres'])->whereHas('genres' ,function ($query) use ($genres){
$query->whereIn('id', $genres);
})->paginate(10);

How to order by column in nested 2 level relationship in Laravel?

I have 3 tables: reports, fields and report_fields which is a pivot between the other 2. What i need to do is order report_field.field by the position column in the field table.
I tried ordering in the relation in the Models or when using with but I may be doing it wrong.
ex:
$query = Report::with([ 'reportFields.field' => function ($q) {
$q->orderBy('position', 'asc');
//$q->orderByRaw("fields.position DESC");
},
Can someone give a basic example of ordering a 2 level nested relationship?
Edit: I do not need to order by any column in the base table but the list of entries in the pivot table by an column in the second table.
Edit2:
To give an example how the output should be ordered:
Report
ReportField
Field.position = 1
ReportField
Field.position = 2
ReportField
Field.position = 3
You can add your needed ordering on the relation of the first table reports:
public function reportFields()
{
return $this->hasMany(ReportFields::class)
->select('report_fields.*')
->join('fields', 'report_fields.field_id', 'fields.id')
->orderBy('fields.position', 'asc');
}

Laravel sort by related table

I have a little complicated relationship and I also want to order my results using column in the other table, let's see:
$book = Book::where('id', '=', $id)->with([
'versions.titles' => function ($query) {
//I want to paginate table "titles"
$query->groupBy('titles.title')->paginate(15);
},
'versions.titles.numbers' => function ($query) {
// but I want to order it by "numbers.order_key"
$query->orderBy('numbers.order_key', 'asc')->get();
}])
->first();
Of course, this code doesn't work properly - titles column isn't sorted by numbers.order_key. Does anybody have any idea how to get it? I don't really want to use joins because of a complication of my relationships.
Update:
My models
Book:
-id
Title:
-id
Version:
-id
-book_id
titles_version:
-title_id
-version_id
Number:
-id
-book_id
-title_id
I want to obtain one nested record to paginate titles, e.g. $book->versions->titles->paginate(15), where titles have to be ordered by numbers.order_key.

Laravel 4: Count relationship within whereHas

I have 2 tables as below:
Subscription table have a entrance_limit column, and it has a hasMany('Attendance') relationship. The entrance_limit column will actually limit the number of rows in Attendance. For example, if the entrance_limit value is 10, then we only can create 10 rows in Attendance.
Attendance table has a belongsTo('Subscription') relationship.
How do I get the list of Subscription that have total number of Attendance less than the entrance_limit value?
Subscription::whereHas('attendances', function($q) {
## something like this
$q->count() < subscription->entrance_limit
})
Model your query has below
Subscription::whereHas('attendances', function($q) {
$q->where('entrance_limit','>',$q->count());
})
Finally able to get it working with the following:
Subscription::whereRaw('
(select count(*) from `attendances` where `attendances`.`subscription_id` = `subscriptions`.`id`) < `subscriptions`.`entrance_limit`
');

Categories