Filter query in Meta table Laravel - laravel

users Tabel
**id|name**
1|xx
users_meta Table
id | user_id | metaKey | metavalue
1 | 1 | city | kolkata
2 |2 |city | london
3 |8 |city |london
My moto is to return users belongs to city London.How can i achive this??

You can query using whereHas:
User::whereHas('users_meta', function ($query) {
$query->where('metavalue', 'london');
})->get();

Lets say u have a relationship with Users and user_meta
Than simply
User::with(['userMeta' => function($query){
$query->where('metaKey', 'city')
$query->where('metavalue', 'london')
}]);
Hope this helps

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();

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 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.

Laravel 4 - Simple join with Eloquent?

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.

Eloquent One-to-Many OrderBy

I'm working with Eloquent on a One-to-Many relationship.
I want to order my Users by using their last post DateTime (created_at) but I can't figure out how to make this work.
Table Users :
id | name
1 | John
2 | Doe
3 | Foo
4 | ...
Table Posts :
id | title | body | user_id | created_at
1 | Title 1| Body1 | 1 | 2014-03-06 14:00:00
2 | Title 2| Body2 | 1 | 2014-03-04 14:00:00
3 | Title 3| Body3 | 2 | 2014-03-03 14:00:00
4 | Title 4| Body4 | 3 | 2014-03-05 14:00:00
Example of final output desired :
name | title | created_at
John | Title 1 | 2014-03-06 14:00:00
Foo | Title 4 | 2014-03-05 14:00:00
Doe | Title 3 | 2014-03-03 14:00:00
The closer I could get was :
$users = User::with(['posts' => function($query){
$query->orderBy('created_at', 'desc');
}])->get();
But this code extracts all the posts for each user and I just want the last one.
Can you help me please? Thanks.
UPDATE : I finally found what I was looking for : Retrieve users' last post and sort the users in ascending order (of this last post's timestamp). Feel free to improve this query!
$users = DB::table('posts')
->join('users', 'posts.user_id', '=', 'users.id')
->select(DB::raw('posts.id, posts.user_id, MAX(created_at) as created_at'))
->groupBy('posts.user_id')
->orderBy('created_at', 'asc')
->get();
You may try this:
$users = User::with(array('posts' => function($query){
$query->orderBy('created_at', 'desc')->groupBy('user_id');
}))->get();
Update: You may try this:
$users = User::join('posts', 'users.id', '=', 'posts.user_id')
->orderBy('posts.created_at', 'desc')
->groupBy('posts.user_id')
->select('users.*', 'posts.created_at as postTime')
->get();
I've only selected created_at from posts table but you may add more fields in select like:
->select('users.*', 'posts.created_at as postTime', 'posts.updated_at as postUpTime', 'posts.id as pid', 'posts.title')
I believe you will either have to use usort() which is a little bit more complicated, or you can use joins, but with that method, you'd also lose the way Eloquent sets up the relations.
Using usort()...
private function cmp($a, $b)
{
if($a->posts->created_at == $b->posts->created_at) {
return 0;
}
return (strtotime($a->posts->created_at) < strtotime($b->posts->created_at)) ? -1 : 1;
}
$users = User::with(array('posts' => function($query){
$query->orderBy('created_at', 'desc')->groupBy('user_id')->first();
}))->get();
$users = usort($users, array($this, 'cmp'));
Or if you would prefer to use joins, I think this should work for you.
$users = DB::table('posts')
->select(DB::raw('MAX(`posts`.`created_at`) AS `created_at`, `user_id`, `users`.*'))
->orderBy('posts.created_at', 'desc')
->groupBy('posts.user_id')
->join('users', 'users.id', '=', 'posts.user_id')
->get();

Resources