Drill down into laravel eloquent relationships - laravel

I have a problem thatโ€™s broken into 2 parts:
1) Iโ€™m trying to get the specific events where rsvps = the logged in user_id.
2) And then filter that where event_date <= today to get the past events.
Iโ€™m getting stuck on #1. When I run
$favorites = Event::with('rsvps')->get();
I get all the events that include the rsvps which is good but I canโ€™t filter it based on the rsvps info.
[
{"id":1,"user_id":"1","created_at":"2016-03-01 02:26:48","updated_at":"2016-03-01 02:26:48","event_name":"Awesome Event","event_venue":"The Rainbow Room","address":"612 Rachael Ln.","event_details":"Epic","event_date":"03\/12","image":"2016-03-01-02-26-48-heartHands.jpg","time":"8:00",
"rsvps":[
{"id":1,"created_at":"2016-03-01 02:28:39","updated_at":"2016-03-01 02:28:39","event_id":"1","user_id":"1"}]
},
{"id":2,"user_id":"1","created_at":"2016-03-01 02:40:05","updated_at":"2016-03-01 02:40:05","event_name":"New Event","event_venue":"My House","address":"612 Rachael Ln.","event_details":"Epic","event_date":"03\/01","image":"2016-03-01-02-40-05-img3.jpg","time":"8:00",
"rsvps":[
{"id":2,"created_at":"2016-03-01 02:40:12","updated_at":"2016-03-01 02:40:12","event_id":"2","user_id":"1"},
{"id":3,"created_at":"2016-03-01 22:21:33","updated_at":"2016-03-01 22:21:33","event_id":"2","user_id":"2"}
]}
]
When I run a test to just get the rsvps with the user_id = 1:
$favorites = Event::with('rsvps')->find('id')->where('rsvps->user_id', '1')->get();
it gives me the error: Call to a member function where() on null
Can someone please give me a clue as to what I'm doing wrong?

You need to query the relationship rsvps. You are trying to query the events.
$favorites = Event::whereHas('rsvps', function($q) {
$q->where('user_id', 1)
})->find('id'); // Passing in 'id' won't work here, it should be the actual id of an event.

Related

Struggle with how to get something from my database with Laravel

๐Ÿ˜„ Hi!
Sorry the title isn't that explicite, but I'm a beginner and I really don't have the vocabulary just yet ๐Ÿ˜ถ
I've been struggling for hours with something, so before I trow my computer by the window, I came to ask for help :3
In my database I have a table with exhibitors and an other one with labels for those exhibitors. It's a many to many relationship and on my Controller I get the exhibitors with they labels that way :
$exposants = Expo::where('this_year', 1)->with('labels')->get();
It's working great! But now I want more!
I need to get the Exhibitors with a specific label. Let's say I want the exhibitors who would come this year with they labels {that part I already have} but only those who have the column "name" on the "label" table equal to "food". How do I do that ? ๐Ÿ˜…
Please help my ๐Ÿ™
You can try
$exposants = Expo::where('this_year', 1)
->whereHas('labels', fn($q) => $q->where('name', $request->input('labelName'))
->with('labels')
->get();
//OR using non-arrow closure for PHP 7.3 and lower
$exposants = Expo::where('this_year', 1)
->whereHas('labels', function($q) use($request){
$q->where('name', $request->input('labelName'));
})
->with('labels')
->get();
//replace labelName with whatever key you have on request
Laravel docs: https://laravel.com/docs/8.x/eloquent-relationships#querying-relationship-existence

Undefined relationship error in sorting of existence and non existence relationship using Eager Load in Laravel eloquent model

I have a Student model and a corresponding one to one mapping relationship to Result model.
I have an eligibleList array containing a list of student id whose marks are to be displayed. Some student have results while some does not have but i need to display all of them from the list.
I am able to retrieve and display students using the following:
$students = Student::with('result:student_id,marks')->whereIn('students.id', $eligibleList)->get();
foreach($students as student) {
if ($student->result != null)
Log::debug($student->result->marks)
else
Log::debug("-1") //-1 indicate no results
}
The above has no issue until i need to sort the list (ascending or descending) by the marks. I tried the following:
$students = Student::with(['result:student_id,marks' => function ($query) {
$query->orderBy('marks','DESC');
}])->whereIn('student.id', $eligibleList)->get();
It throws me a "Call to undefined relationship" error. Is there anyway to sort from the query ? I avoid sorting the collection as it can get very slow for thousands of records. Somehow eloquent early loading encounter some error when sorting with non existence relationship.
you should use 'Subquery Ordering', ordering inside 'with' will not sort the overall result.
$students = Student::with(['result:student_id,marks'])->whereIn('student.id', $eligibleList)
->orderByDesc(Result::select('marks')->whereColumn('student_id','students.id'))
->get();
https://laravel.com/docs/7.x/eloquent#advanced-subqueries
if you use laravel 5 you have to use 'join':
Student::with(['result:student_id,marks'])->whereIn('student.id', $eligibleList)
->join('result','result.student_id','student.id')
->select('user.*,result.marks')->orderBy('result.marks')->get();
'join' use table name not the relation name, so please be careful about table name in previous 'join' and 'select' statements

How can i convert this sql query in a eloquent laravel command?

in sql query this commando do exactly i wanted:
SELECT
v.id,
(
SELECT sv.status_id
FROM status_viagem sv
WHERE sv.viagem_id = v.id
ORDER BY sv.created_at DESC LIMIT 1 ) AS status_id
FROM viagens v
Here is the sql results:
But i have no idea how can i do this using Laravel eloquent
Basically, a viagem entry can has a lot of status, but i need to get each viagem and their last status entry from status_viagem table (the pivot table)
by the way viagem/viagens means travel.
My class mapping:
class Viagem extends Model
{
...
public function status()
{
return $this->belongsToMany('App\Status')->withTimestamps();
}
...
}
class Status extends Model
{
public function viagens()
{
return $this->belongsToMany('App\Viagem')->withTimestamps();
}
}
The belongsToMany at both classes gets me a many-to-many:
can someone help me? thanks
---------- Temporary Solution -------
Thanks for all help guys. In fact i can't find a nice solution using only eloquent.
Step 1/3 - To bypass this situation i first execute the above sql to grab only the viagens under the desired status_id (last status_viagem entry):
$viagens_ids = DB::select(
"SELECT viagem_id FROM (
SELECT
v.id AS viagem_id,
(
SELECT sv.status_id
FROM status_viagem sv
WHERE sv.viagem_id = v.id
ORDER BY sv.id DESC LIMIT 1 ) AS status_id
FROM viagens v
) AS tt
WHERE tt.status_id = {$status->id}"
);
Step 2/3 - then i used the array_map to organize my viagens ids
$a = array_map(
function($obj) { return $obj->viagem_id; },
$viagens_ids
);
Step 3/3 - And at last i used elequent whereIn to fetch my viagens:
Viagem::with( 'status')->whereIn('id', $a)->get();
In fact i have solved the problem by a-old-sashion-way but i not happy with it because i wish i learn how to do it using eloquent. what bad to me.
There are many ways to query in laravel. I have created a test project for you to try. The gist are:
1. Eloquent ORM
Eloquent ORM is Laravel's magic which have some limitations in eager loading - which i just come across while contemplating your question for hours. It wont play nicely with first(), last(), and some more functions in the constrained eager loading closure.
In your case, our almost there can be fixed:
App\Models\Viagem::with(['status' => function($query){
return $query->orderBy('pivot_created_at', 'desc');
}])
->get()
It will return entire field for Viagem and Status including its pivot table (the status_viagem).
However, if you wanted to retrieve only viagem.id and status_viagem.status_id, you can map() it as such:
App\Models\Viagem::with(['status' => function($query){
return $query->orderBy('pivot_created_at', 'desc');
}])
->get()
->map(function($data){
$o = new stdClass();
$o->id = $data->id;
$o->status_id = $data->status->first()->id;
return $o;
});
Please take note that the statement above require sql query to be ran twice. Eager loading basically works by querying all the Viagem first then queries the Status and map them in memory based on the foreign keys. You can observe that replacing get with toSql will only give you the first query. Please enable Query Logging to see the second query.
2. Query Builder
Embarking from Ryan Adhitama Putra answer, you could do something like:
App\Models\Viagem::join('status_viagem', 'viagens.id', '=', 'status_viagem.viagem_id')
->orderBy('status_viagem.created_at', 'desc')
->groupBy(['status_viagem.status_id', 'viagens.id'])
->select(['viagens.id', 'status_viagem.status_id'])
->get();
This query builder approach guaranteed to be ran only once, you can replace the get() with toSql() to see the resulting query.
3. Raw Queries
Throwing DB::raw() can help sometime, but i really did not want to mention it.
I am not sure what viagens and viagem represent, but I think one of the relationships has to be belongsToMany() and the other hasMany().
then after you set relationships correctly, you can use Eloquent like this :
$status_id = Viagem::with('status')->orderBy('created_at', 'desc')->first()->pluck('status_id');
Try this.
$status_id = Viagem::join('status','viagem.id','status_viagem.viagem_id')
->select('viagem.id','status_viagem.status_id')
->get();

Laravel update query use

I used this query to update the status column.
$val="1";
vehicles::where('id' , '=' , $veh_status)->update(['status' => $val]);
But when I submitted the status value doesn't change.
you can trace your query by using ->toSql() method !
try this to find whats happening in back
Not sure what the problem is there because you haven't given much info to work with, but you can check these suggestions:
Check if the column is set to be mass assignable in the model class, that is, it is in the fillable[] array.
make sure the id you pass to the where() function is valid.
Try using another function, save() which will achieve the same results you seek, like this;
// filter the vehicle
$vehicle = vehicles::where('id', '=', $veh_id)->first();
or
$vehicle = vehicles::find($veh_id);
$vehicle->status = 1;
$vehicle->save();
Lastly, I noticed your id variable you pass to the where the () function is called $veh_status "presumably - vehicle status" and not $veh_id, "presumably - vehicle id" so probably check that out.
Ref: Laravel Model Update documentation

Laravel Order by in one to many relation with second table column

Hi i have tables with one to many relation
sectors
id
name
position
seat_plans
id
name
sector_id
I just want to select all seat plans order by sectors.position. I tried
$seat_plans = SeatPlan::with(['sector' => function($q){
$q->orderBy('position');
}
])->get();
but it is not working. when i check The SQL it is generating query like
select * from seat_plans
can anybody please tell me how to do this?
I don't think you need a custom function for your use case. Instead try this:
$users = DB::table('seat_plans')
->join('sectors', 'seat_plans.sector_id, '=', 'sectors.id')
->select('seat_plans.*')
->orderBy('sectors.position')
->get();

Resources