Laravel 4 - Simple join with Eloquent? - laravel-4

I'm simply trying to join 2 tables with Laravel 4's Eloquent ORM. The tables are:
TABLE: PRODUCTS
ID | CATEGORY_ID | NAME
-------------------------
1 | 2 | Hammer
2 | 2 | Saw
3 | 1 | Apple
TABLE: CATEGORIES
ID | NAME
-----------
1 | Food
2 | Tools
Of course this can be done with SQL:
SELECT products.name, categories.name
FROM products
INNER JOIN categories ON products.category_id = categories.id
And this will output:
Hammer | Tools
Saw | Tools
Apple | Food
But is there an easier way to get the same result using Laravel's Eloquent, maybe using the build-in table relationships?

Set up a many-to-one relation in your models:
Category.php
public function products() {
return $this->hasMany('Product');
}
Product.php
public function category() {
return $this->belongsTo('Category');
}
Then call:
$products = Product::with('category')->get();
For each element of the result, $products->name and $products->category->name will contain your fields.

Related

Laravel running multiple queries instead of join in Eloquent

I am trying to run join between my pages table and users table. Means one user can create multiple pages and in pages table created_by column belongs to my users table column id.
Table Structure:
---------------------------------------------
id | page_title | page_desc | created_by |
---------------------------------------------
1 | Testing | Descripti | 1 |
---------------------------------------------
2 | New Page | Desc | 2 |
User table
-------------------------------------------
id | name | email | pass | created_at |
-------------------------------------------
1 | A | a#g.c | 123 | 2017-10-21 |
-------------------------------------------
2 | B | b#g.c | 123 | 2017-10-21 |
in my Page model i used:
public function createdBy(){
return $this->belongsTo('App\User','created_by','id');
}
now when i am trying to get the data with:
$model = Page::all()
foreach($model as $key => $value){
echo $value->createdBy->name."<br/>";
}
laravel generating multiple queries to get name of each user is that any way to run the join instead of multiple queries?
You're running into the N+1 problem. You need to eager load your relationship to resolve this. You can read more on eager loading here.
Use the with() method on the page query to eager load all the related user records for each page:
$model = Page::with('createdBy')->get();
foreach ($model as $key => $value) {
echo $value->createdBy->name."<br/>";
}
This will now only run 2 queries: one to get all the pages, and one to get all the users related to each page.
For that reason Laravel provides eager Loading
Eager Loading
When accessing Eloquent relationships as properties, the relationship data is "lazy loaded". This means the relationship data is not actually loaded until you first access the property. However, Eloquent can "eager load" relationships at the time you query the parent model
For more info just check this link.
OR Just Use Laravel's database query builder
You can perform join directly on your Table and fetch directly the data
$users = DB::table('pages')
->join('users', 'pages.created_by', '=', 'users.id')
->select('users.name','users.email', 'pages.*') //Specify what parameters you want.
->get();
To Join queries you can use laravel query builder like below
$pages = DB::table('pages')
->join('users', 'pages.created_by', '=', 'users.id')
->select('users.*', 'pages.*')
->get();

Select records where not in relational table

I have 2 tables with this structures :
**table1**
id | title
-----+--------
1 | Blah1
2 | Blah2
**table2**
id | table1_id | article_id
-----+-------------+------------
1 | 1 | 1
2 | 1 | 3
3 | 2 | 1
Now I want to know how can I select all records from table1 where not use in table2
for example I need all table1 records where not exists in table2 for article_id=3
How can I create model and use eloquent models ?
UPDATE:
I need Blah2 from table1 and then show to my user, because Blah1 inserted for article_id = 3 before.
UPDATE 2:
This is worked query, I need write model for this query:
SELECT a.*
FROM table1 AS a
WHERE a.id NOT IN (SELECT table1_id
FROM table2
WHERE article_id = 3
)
you need to create model something like below you can change name appropriately
here i will refer something like below
table1 => ParentModel and table2 => ChildModel
define relation for children in ParentModel with below method
class ParentModel extends Model {
public function children() {
return $this->hasMany(ChildModel::class, 'table1_id');
}
}
whereDoesntHave method is available to filter records with related model
check here https://laravel.com/docs/5.3/eloquent-relationships#querying-relationship-absence
ParentModel::whereDoesntHave('children', function($q){
// here $q refers to related model in this case ChildModel
$q->where('article_id', 3);
})->get();
above query should return the required results.

How to eagerload an array of values from a belongsTo relationship

I have 3 tables representing a many to many (belongsToMany) relationship between User and Group and GroupUser as the pivot table. What I would like to do is simply display all users that are NOT a member of group_id 2.
User model GroupUser model (pivot table) Group model
ID|name ID|user_id|group_id ID|group_name
1 |Mark 1| 1 |2 1| the sharks
2 |Sam 2| 3 |1 2| the tigers
3 |Sally 3| 2 |3 3| the whales
4 |Tim 4| 4 |2
My solution
Create a belongsTo (hasMany) relationship between User and GroupUser so GroupUser belongsTo User and then eager load all users that are not a member of group_id 2.
How would I go about writing the code in my controllers and viewing this in blade?
Before I use the WhereNotIn condition I'm trying to simply eager load all users. So far I have this but for some reason it's only reading the last line in the group_user table.
foreach (GroupUser::with('belongstomethod')->get() as $query)
{
$query->belongstomethod->name;
}
The result from the code above is Tim
This will display all the users that are not part of group_id = 2.
Controller or repository:
$group_id = 2;
$users = User::whereHas('groups',function($query) use($group_id) {
$query->where('id','!=',$group_id);
})->get();
return view('your_view',compact('users')); //this will pass the $users collection to the view.
View (using blade):
#foreach($users as $user)
{{$user->name}}
{{$user->etc}}
#endforeach
This code assumes you have a public method called "groups" on your User Model. And that the method returns a belongsToMany relationship.

How can I define an Eloquent relationship using MySQL functions?

I'm having trouble defining a relationship in Eloquent. I have two tables.
The first table contains email domains. Here is an example:
+-------+----------------+-----------+
| ed_id | ed_domain | ed_isp_id |
+-------+----------------+-----------+
| 17 | | 6 |
| 13 | aim.com | 1 |
| 12 | aol.com | 1 |
+-------+----------------+-----------+
The second table contains information about my users, one of the columns being an email address.
I have tried to set this up using...
public function users()
{
return $this->hasMany('Leadgen\Lead', \DB::raw('SUBSTRING_INDEX(l_email, \'#\', -1)'), 'ed_domain');
}
What I expected to happen is something like the following:
LEFT OUTER JOIN email_domains ON SUBSTRING_INDEX(email, '#', -1) = ed_domain
What I receive though is a SQL error.
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'leads.SUBSTRING_INDEX(l_email, '#', -1)' in 'where clause' (SQL: select * from `leads` where `leads`.`SUBSTRING_INDEX(l_email, '#', -1)` in (aol.com))
You cannot use the standard Laravel relations as they require to have related tables having foreign keys paired to primary keys. What you can do is to do the LeftJoin using query builder and return the users manually.
public function users() {
return DB::table('users as u')
->leftJoin('email_domains as ed', DB::raw('SUBSTRING_INDEX(u.email, \'#\', -1)'), '=', 'ed.ed_domain')
->select('u.*');
}
This function will return query builder object so you can do further chaining according to your requirements and finally use ->get() to have the final result. I have not actually run the code but basically this is what you need to do.

How in query Eloquent specify condition with relations

I have 2 tables:
articles
id | title | category_id | created_at | updated_at |
and categories
id | name | descriptions | created_at | updated_at |
Relations : category hasMany-> articles and articles belongsTo -> category.
how simple way make query something like :
public functions getArticles ($category) {
$articles = Articles::where('category', '=', $category);
}
In documentations exist example with Id (http://laravel.com/docs/4.2/eloquent#one-to-many ) , but I want select articles, knowing name category.
How in query specify condition with relations ?
If exist such methods, please help me.
Thanks ;)
You can use whereHas method. Like:
$articles = Articles::whereHas('category', function($query)use($category){
$query->where('name', $category->name);
});
I suppose that should work. Or you can just create a scope and join categories table and then check by it.

Resources