How can I write the join query using eloquent ORM of Laravel - laravel

Currently I have three tables one is property table having following columns:
id
name
description
2nd is tags table having following colums:
id
tag_name
tag_status
3rd is the pivot table having following columns:
id
tag_id
property_id
Now in Property Model I have defined the relation with pivot table like this:
public function tags()
{
return $this->belongsToMany('Tag');
}
and in Tag Model I have defined the relation with pivot table like this:
public function properties()
{
return $this->belongsToMany('Property');
}
Now what I need to now is how can I write the following query on these three tables using eloquent ORM of Laravel:
$propertyTags=Property::join('property_tag', 'properties.id', '=', 'property_tag.property_id')
->join('tags', 'tags.id', '=', 'property_tag.tag_id')
->where('properties.id','=',$property_id)
->get(['tags.tag_name','tags.id']);

you can try
$property_obj = Property::find($property_id);
$property_tags = $property_obj->tags->all();
or using eager loading
$property_with_tags = Property::with('tags')->where('id','=',$property_id)->get();

Related

laravel eloquent with pivot and another table

I have 4 table categories, initiatives, a pivot table for the "Many To Many" relationship category_initiative and initiativegroup table related with initiatives table with initiatives.initiativesgroup_id with one to many relation.
With pure sql I retrive the information I need with:
SELECT categories.id, categories.description, initiatives.id, initiatives.description, initiativegroups.group
FROM categories
LEFT JOIN category_initiative ON categories.id = category_initiative.category_id
LEFT JOIN initiatives ON category_initiative.initiative_id = initiatives.id
LEFT JOIN initiativegroups ON initiatives.initiativegroup_id = initiativegroups.id
WHERE categories.id = '40'
How can I use eloquent model to achieve same results?
Since you have such a specific query touching multiple tables, one possibility is to use query builder. That would preserve the precision of the query, retrieving only the data you specifically need. That would look something like this:
$categories = DB::table('categories')
->select([
'categories.id',
'categories.description',
'initiatives.id',
'initiatives.description',
'initiativegroups.group',
])
->leftJoin('category_initiative', 'categories.id', '=', 'category_initiative.category_id')
->leftJoin('initiatives', 'category_initiative.initiative_id', '=', 'initiatives.id')
->leftJoin('initiativegroups', 'initiatives.initiativegroup_id', '=', 'initiativegroups.id')
->where('categories.id', '=', 40)
->get();
In your models define the relationships:
Category.php model
public function initiatives()
{
return $this->belongsToMany('App\Initiative');
}
Initiative.php model (If has many categories change to belongs to many)
public function category()
{
return $this->belongsTo('App\Category');
}
Then maybe change your initiativegroup -> groups table, and then create a pivot table called group_initiative. Create model for group. Group.php and define the relationship:
public function initiatives()
{
return $this->belongsToMany('App\Initiative');
}
Then you can also add the following relationship definition to the Initiative.php model
public function group()
{
return $this->belongsTo('App\Group');
}
That should get you started.
for the record..
with my original relationship, but changing table name as alex suggest, in my controller:
$inits = Category::with('initiative.group')->find($id_cat);
simple and clean

Get only one column from relation

I have found this: Get Specific Columns Using “With()” Function in Laravel Eloquent
but nothing from there did not help.
I have users table, columns: id , name , supplier_id. Table suppliers with columns: id, name.
When I call relation from Model or use eager constraints, relation is empty. When I comment(remove) constraint select(['id']) - results are present, but with all users fields.
$query = Supplier::with(['test_staff_id_only' => function ($query) {
//$query->where('id',8); // works only for testing https://laravel.com/docs/6.x/eloquent-relationships#constraining-eager-loads
// option 1
$query->select(['id']); // not working , no results in // "test_staff_id_only": []
// option 2
//$query->raw('select id from users'); // results with all fields from users table
}])->first();
return $query;
In Supplier model:
public function test_staff_id_only(){
return $this->hasMany(User::class,'supplier_id','id')
//option 3 - if enabled, no results in this relation
->select(['id']);// also tried: ->selectRaw('users.id as uid from users') and ->select('users.id')
}
How can I select only id from users?
in you relation remove select(['id'])
public function test_staff_id_only(){
return $this->hasMany(User::class,'supplier_id','id');
}
now in your code:
$query = Supplier::with(['test_staff_id_only:id,supplier_id'])->first();
There's a pretty simple answer actually. Define your relationship as:
public function users(){
return $this->hasMany(User::class, 'supplier_id', 'id');
}
Now, if you call Supplier::with('users')->get(), you'll get a list of all suppliers with their users, which is close, but a bit bloated. To limit the columns returned in the relationship, use the : modifier:
$suppliersWithUserIds = Supplier::with('users:id')->get();
Now, you will have a list of Supplier models, and each $supplier->users value will only contain the ID.

Eloquent hasMany with foreign key on joint table

Assume this:
class List extends Model
{
public function items(){
return $this->hasMany(Items::class, 'c.class_id', 'class_id')
->rightjoin('items_classes as c', 'c.items_id', '=', 'items.id');
}
}
The problem is that Eloquent prepends items to foreign key field and the final query is:
SELECT * FROM items
RIGHT JOIN items_classes as c ON c.items_id = items.id
// here it is
WHERE items.c.class_id = 10
Even using DB::raw('c.class_id') didn't solve the problem.
If you notice the signature of hasMany relation method :
return $this->hasMany(Model::class, 'foreign_key', 'local_key');
Which means when Laravel will make the query, it will consider second argument foreign_key as a column of table defined in Model::class.
To simplify in your case :
return $this->hasMany(Items::class, 'c.class_id', 'class_id')->...
Leaving the rightjoin aside for a moment, Laravel is considering c.class_id as a foreign key of Item::class table which is indeed items table.
So the resultant query is :
SELECT * FROM items WHERE items.c.class_id = 10
Then when you add the right join, laravel just adds into the main query and makes it :
SELECT * FROM items
RIGHT JOIN items_classes as c ON c.items_id = items.id
WHERE items.c.class_id = 10
Laravel will not refer items_classes in the relation because you are relating List Model to Item::class and not ItemClass::class.
I am not sure about the data you need but see if you can use with like below :
class List extends Model
{
public function items(){
return $this->hasMany(Items::class, 'c.class_id', 'class_id');
}
}
List::with(['items', function($q){
return $q->->rightjoin('items_classes as c', 'c.items_id', '=', 'items.id');
}])->get();
Hope this gives you an idea how you can update your relationships to get desired query. If you add your table structure and data you want, I can update the answer with relationships for you.

Laravel Fetching one to Many Relationship

Hello I am learning laravel and I am having an issue retrieving data from my relations.
In my database there are Product and Groups filled with dummy data.
I defined my relationship like this in product model:
public function Group()
{
return $this->hasMany('App\Groups','product_id', 'id');
}
And in my group vice versa with :
public function Product()
{
return $this->belongsTo('App\Product','product_id', 'id');
}
The way I am referencing to my products table is :
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
Now I have column product_id in my database under groups, and it is linked to if from products id it seems.
The groups table contains of its auto incremented id and product_id foreign key column.
While products table has auto incremented id and name column.
The issue is here :
How do I return the products that are not null or have value (of products id) in groups table.
I tried something like this in my filter controller:
public function getProductsWithGroup()
{
$Products = Product::with('groups')->get();
return $Products ;
}
But that is giving me call to undefined relations.
I am not sure how to access belongsTo or hasMany methods and whether I need an extra group_id column in my products table.
You named the relationship wrong. It should be groups & define in lowercase as
public function groups()
{
return $this->hasMany('App\Groups','product_id', 'id');
}
And use ->has() to check existence
public function getProductsWithGroup()
{
$Products = Product::has('groups')->get();
return $Products ;
}
->with() is used to eager load and ->has() is used to check existence & filter.
To get the products don't have any groups,
$Products = Product::doesntHave('groups')->get();
To see other ways to use ->has() check, https://laravel.com/docs/5.7/eloquent-relationships#querying-relationship-existence

Laravel eloquent table joined to itself, how to get 1 array with all values

I am using a table employee that is joined to itself for the manager.
Employee
id
name
manager_id (FK to Employee)
I am using the following model for Employee:
public function my_employees()
{
return $this->hasMany('App\Employee', 'manager_id');
}
public function my_manager()
{
return $this->belongsTo('App\Employee', 'manager_id');
It is working fine because I can use the my_employees function on an employee and it will get me all the records linked to this employee.
Now I would like to get a table with all the employees where the column manager_id is replaced by manager_name. How can I achieve this with Eloquent?
Not using Eloquent, I do:
$employee = DB::table('employee')
->select('employee.id', 'employee.name', 'employee.manager_id','manager.name AS manager_name')
->join('employee AS manager', 'employee.manager_id','=','manager.id');
This gets me of course what I want but I would like to understand how to do it with Eloquent only.
Thanks.
Exactly the same way.
$employees = Employee::select('employee.id', 'employee.name', 'employee.manager_id', 'manager.name AS manager_name')
->join('employee AS manager', 'employee.manager_id', '=', 'manager.id')
->get();
You could also do this shown below. But then you need to access the manager name from the relationship object.
$employees = Employee::with('my_manager')->get();
foreach($employees as $employee) {
echo $employee->my_manager->name;
}
Edit
You can add any constraint to the eager loaded relationship.
$employees = Employee::with(['my_manager' => function($query) {
$query->select('manager_id', 'name');
}])->get();

Resources