Speed up query through laravel relationships - php

There are 3 models:
First (first_id)
Connection (connection_id, first_id, product_id)
Second (second_id, product_id)
I would like to connect the three models together using laravel relationships
First->joined to Connection though first_id
Connection->joined to First through first_id, & joined to Second through product_id
Second -> joined to Connection through product_id
So: First joined to Second through Connection first_id, product_id
Is this possible to do using something like HasManyThrough?
Thanks for your time

On your First model:
public function second () {
return $this->hasManyThrough(
Second::class,
Connection::class,
'product_id', // Foreign key on connection table
'product_id', // Foreign key on second table
'first_id', // Local key on first table
'first_id' // Local key on connection table
);
}
Based on your description the column names should work.
In tinker you can validate if it's hooked up correctly by doing something like First::first()->second.

It depends on what type of relationship Your first model and second model shares as well as what type of relation second and third model shares.
if consider your first model First and second model Second shares a one-to-one relation, as well as Second model and Third models shares one-to-one relationships.
It will be $first->second->third; //no has many through relationship requires
If your First model and Second models shares as hasMany-belongs to relation than you need to use hasManyThrough relationship
example from doc
class Country extends Model
{
public function posts()
{
return $this->hasManyThrough(
'App\Post',
'App\User',
'country_id', // Foreign key on users table...
'user_id', // Foreign key on posts table...
'id', // Local key on countries table...
'id' // Local key on users table...
);
}
}

You can try using nested relationships.
Nested Eager Loading
To eager load nested relationships, you may use "dot" syntax. For example, let's eager load all of the book's authors and all of the author's personal contacts in one Eloquent statement:
$books = App\Book::with('author.contacts')->get();
Book Model:
public function author()
{
return $this->hasOne('App\Author');
}
Author Model:
public function contacts()
{
return $this->hasMany('App\Author');
}
Documentation:
https://laravel.com/docs/5.8/eloquent-relationships

Related

Laravel belongsToMany retrieve more then one row

So im creating a booking system where you can create maps and assign them to an event. I have 3 tables to handle this, events, maps, and event_maps
I have after reading the Laravel Documentation i decided to set up a belongsToMany relation.
But when i try to retrieve my maps thru my event model i only get one the first row.
in my controller i do
public function displayForm($id)
{
$event = EventModel::find($id);
print_r($event->maps);
}
The result is a Illuminate\Database\Eloquent\Collection Object with the last out of 2 maps, and i can't for my life figger out how to get them all.
My EventsModel
public function maps()
{
return $this->belongsToMany('App\Models\Booky\MapsModel',
// Table name of the relationship's joining table.
'event_maps',
// Foreign key name of the model on which you are defining the relationship
'map_id',
// Foreign key name of the model that you are joining to
'event_id'
);
}
My MapsModel
public function event()
{
return $this->belongsToMany('App\Models\Booky\EventsModel',
// Table name of the relationship's joining table.
'event_maps',
// Foreign key name of the model on which you are defining the relationship
'event_id',
// Foreign key name of the model that you are joining to
'map_id'
);
}
The database looks something like this
events
- id
- lots of irrelevant data
maps
- id
- lots of irrelevant data
event_maps
- id
- event_id
- map_id
I was thinking that perhaps i should use another relation type, but as far as i understand they don't use a relation table like event_maps.
Everything else work as expected.
Anyone who could clear up this mess? :)
The ids are inverted in the relation. Try this:
public function maps()
{
return $this->belongsToMany('App\Models\Booky\MapsModel',
// Table name of the relationship's joining table.
'event_maps',
// Foreign key name of the model that you are joining to
'event_id'
// Foreign key name of the model on which you are defining the relationship
'map_id',
);
}
And:
public function event()
{
return $this->belongsToMany('App\Models\Booky\EventsModel',
// Table name of the relationship's joining table.
'event_maps',
// Foreign key name of the model that you are joining to
'map_id'
// Foreign key name of the model on which you are defining the relationship
'event_id',
);
}

getting all the data from pivot table in laravel

i'm trying to get all the lead_id inside my pivot table but i can't make it work.
controller:
$levels = Level::all();
$levels->lead()->attach('lead_id');
return $levels;
Model Level:
public function lead(){
return $this->belongsToMany(Lead::class, 'level_students')->withPivot('level_id', 'lead_id');
}
Model Lead:
public function level(){
return $this->belongsToMany(Level::class, 'level_students')->withPivot( 'lead_id', 'level_id');
}
If you mean all lead_id of a Level, then you can use pluck().
$level->lead->pluck('lead_id');
I'm not really sure what you are trying to achieve because it seems that you want to retrieve all lead_id associated with any Level. But if that is the case, then you can create a model for the pivot table (e.g. LevelLead) and use distinct() or with Query Builder:
$leadIds = DB::table('level_students')->select('lead_id')->distinct()->get();
If you want to get the referenced table's column (e.g. leads table's name column) then you can use JOIN. Check Laravel's doc for more options. For example, assuming the table name for Lead is leads, then:
$leads = DB::table('level_students')->join('leads', 'level_students.lead_id', '=', 'leads.lead_id')->select('level_students.lead_id', 'leads.name')->distinct()->get();

Laravel hasManyThrough 2 tables

i have two tables as below:
users table:
|id|name|email|password|created_at|updated_at
messages table:
|id|sender_id|receiver_id|message|created_at|updated_at
User model:
public function threads()
{
return $this->hasManyThrough(Message::class, User::class,'id','sender_id');
}
i'm trying retrieve message threads
which isn't working. any help appreciated.
This is an example from laravel eloquent relationship
class Country extends Model
{
public function posts()
{
return $this->hasManyThrough(
'App\Post',
'App\User',
'country_id', // Foreign key on users table...
'user_id', // Foreign key on posts table...
'id', // Local key on countries table...
'id' // Local key on users table...
);
}
}
can you review your code
It seems that you want to retrieve all messages that belongs to a single thread (list of users) using hasMany relationship Through User model, to do that You have to define hasManyThrough inside Thread model not in User model, here is an example:
User:
|id|name|email|password|created_at|updated_at|thread_id
Note thread_id foreign key because thread is a list of users
Thread:
class Thread extends Model {
public function messages() {
return $this->hasManyThrough(Message::class, User::class,'thread_id','sender_id', 'id', 'id');
}
}
Example from laravel doc

Laravel - hasManyThrough return only _id

I use Laravel MongoDB package by jenssegers and Eloquent Laravel Model.
articles :
_id (ObjectID)
feed_id
title
feeds :
id
user_id
name
users :
id
name
hasManyThrough in User::class model to get all articles by one user.
public function articles()
{
return $this->hasManyThrough(
'App\Article',
'App\Feed',
'user_id', // Foreign key on feeds table...
'feed_id', // Foreign key on articles table...
'_id', // Local key on users table...
'id' // Local key on feeds table...
);
}
I get only _id (ObjectID) with this query:
$user = \App\Models\User::find(1);
dd($user->articles);
Could you help me to search the problem?
You can try this
$user->articles()->find(1);
In place of find() you can use first() if you want the first record and if you want all records you can use get()
also if you want to put constraint use where() rather than find()
$user->articles()->where('_id', 1)->first();

Retrieve distant relation through has-many-through for many-to-many relation in Laravel

I have the following models in my application
User
Group
Task
which have the following relationships
User and Group have a many-to-many relationship
Task and Group have a many-to-many relationship
So basically a user can belong to more than one group and each group can have more than one task.
Following is the table structure.
users
id
name
groups
id
name
tasks
id
name
group_user
id
group_id (foreign key with groups table)
user_id (foreign key with users table)
group_tasks
id
group_id (foreign key with groups table)
task_id (foreign key with tasks table)
Now I want to retrieve all the tasks for the user.
I tried the following approaches and both didn't work.
Approach 1
$user->groups() gives the list of groups for a user
$group->tasks() gives the list of tasks for a group
So I tried
$user->groups()->tasks() but it didn't work.
Approach 2
I tried Has Many Through by adding this to my User model
public function tasks()
{
return $this->hasManyThrough(Task::class, Group::class);
}
but even that didn't work. The following is the error that I am getting
QueryException in Connection.php line 713:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'groups.user_id' in 'field list' (SQL: select `tasks`.*, `groups`.`user_id` from `tasks` inner join `groups` on `groups`.`id` = `tasks`.`group_id` where `groups`.`user_id` = 1)
My guess is that this is happening because it is expecting one-to-many relationship, but I have a many-to-many relationship.
So is there a way to retrieve it without getting all groups and then looping through them?
User Model
public function groups()
{
return $this->belongsToMany('App\Group');
}
Group Model
public function tasks()
{
return $this->belongsToMany('App\Task');
}
Task Model
public function groups()
{
return $this->belongsToMany('App\Group');
}
Retrieving all tasks for a user.
$user = User::find(1);
$user->load('groups.tasks');
$tasks = $user->groups->pluck('tasks')->collapse();
You can also take a look at the extension of the HasManyThrough here: https://github.com/staudenmeir/eloquent-has-many-deep
It helps you to retrieve many sub-levels of your relationships.
In your case, it would be
User -> belongsToMany(Groups) -> blongsToMany (Tasks)
just add your method to the user model like:
public function tasks()
{
return $this->hasManyDeep(
'App\Task',['App\Group']
);
}

Categories