I have three models namely Users, Posts and Comments.
Users table
id username active
1 guyd 1
2 mohok 0
3 cotra 0
Posts table
id post_content user_id
1 Hello 1
2 World 2
3 Foo 3
Comments table
id post_id user_id commment_body
1 1 2 Great post
2 1 3 Totally disagree
3 2 1 Nice read
4 2 3 Wow
5 1 1 Thanks guys
My Posts Model has
public function latestComments($limit = 3)
{
return $this->hasMany(Comment::class)
->where('voided', '=', 0)
->with('user')
->join('users as comment_owner', 'comments.user_id', '=', 'comment_owner.id')
->where('comment_owner.active', '=', 1)
->orderByDesc('comments.updated_at')
->limit($limit);
}
My Comments model has
public function user()
{
return $this->belongsTo(User::class);
}
I want to fetch only posts and comments from users whose active=1. I am using the following but it's giving the wrong results. It's assigning comments to posts without comments.
$posts = Post::orderBy('posts.created_at', 'DESC')
->with('user')
->with('latestComments')
->join('users as post_owner', 'posts.user_id', '=', 'post_owner.id')
->where('active', 1)
->paginate(5);
You should use whereHas()
Post::latest()
->with('user', 'latestComments')
->whereHas('user', function ($q) {
$q->where('active', 1);
})
->paginate(5);
If you also want to filter comments:
->with(['user', 'latestComments' => function ($q) {
$q->whereHas('user', function ($q) {
$q->where('active', 1);
});
}])
Related
I have the relationship below, an application belongs to a user.
Users table
ID | Name
1 | Danny
2 | Mark
Applications table
ID | user_id
1 | 1
2 | 2
Application.php
public function user()
{
return $this->belongsTo(User::class);
}
I'm trying to sort the application by user's name and paginate the result. I tried the code below, the pagination is working but the order by doesn't have any effect.
$query = Application::query();
$query = $query->with(['user' => function ($query){
$query->orderBy('name', 'DESC');
}]);
$query = $query->paginate(10);
Try using inner join and order by relation column:
$applications = Application::select('*')
->join('authors', 'applications.user_id', '=', 'users.id')
->orderBy('authors.name', 'DESC')
->paginate(10);
Try this:
Application::join('users', 'applications.user_id', '=', 'users.id')
->orderBy('users.name','desc')
->with('users')
->get();
I have two tables and relations as bellow
user
the user table:
id
name
active
1
abc
1
2
xyz
Null
3
abx
0
the book table:
id
user_id
name
active
1
1
book1
0
2
2
book2
0
3
1
book3
0
relation is as this
user->books (HasMany)
return $this->hasMany(Book::class,'user_id','id');
my query is as bellow
User::with('book')
->WhereHas('book', function($query) {
$query->where(['active'=> 1]);
})
->where(['id'=> 1,'active'=>1])
->get();
This query is getting zero records because active is 0 in books
But i want to see all user record and if there is matching record with active 1 in book.
second is query user for active 1 or Null and for that if use ->orwhereNull('active')
All records changes.
Thanks
I guess you need to apply filter on related records (with()) instead of applying filter on whole query. So this way you will always get a list of users along with the list of active books only
User::with(['book'=> function($query) {
$query->where('active', 1);
}])
->where(function ($query) {
$query->where('active', 1)
->orWhereNull('active');
})
->get();
I have used logical grouping here so in case if you have more filter clauses to add in your query.
Or you can define a new relation in your user model to pick only active related books as
class User extends Model
{
public function book()
{
return $this->hasMany(Book::class, 'user_id', 'id');
}
public function active_books()
{
return $this->hasMany(Book::class, 'user_id', 'id')
->where('active', '=', 1);
}
}
User::with('active_books')
->where(function ($query) {
$query->where('active', 1)
->orWhereNull('active');
})
->get();
You have id and active column on both table, so I think you need to change your query like this :
User::with('book')
->WhereHas('book', function($query) {
$query->where(['books.active'=> 1]); // books table active column
})
->where(['id'=> 1,'active'=> 1]) // users table id, active column
->get();
i want to get users with last messages with another user
users table
id
1
2
messages table
user_id user_reciever_id
1 2
1 2
2 1
2 1
i want get all users that:
messages.user_id=auth::id() and messages.user_reciever_id=users.id
or
messages.user_reciever_id=auth::id() and messages.user_id=users.id
how to handle it with hasmany. thanks alot.
You can do like this =>
public function messages() {
return $this->hasMany('App\Messages', 'user_id' , 'id');
}
public function filteredmessages() {
return $this->messages()->where(// condition)
->where(// condition);
}
$user = User::with('filteredmessages')->get();
print_r($user);
Or you Can use whereHas like this :
$id = auth::id();
$user = User::whereHas('messages', function($q) use ($id){
$q->where('user_id', $id);
$q->where(// additional conditions)
})->get();
Let me know if it helps
Question. How can I use Eloquent to produce this query:
SELECT campaigns.name, users.name FROM campaigns LEFT JOIN users on campaigns.gamemaster_id = users.id where campaigns.status = 1
Campaigns
id gamemaster_id name status
1 1 campaign1 1
2 2 campaign2 1
Users
id name
1 rick
2 bob
Result
id gamemaster_id name status gamemaster_name
1 1 campaign1 1 rick
2 2 campaign2 1 bob
Campaign model
class Campaign extends Model
{
public function gamemaster()
{
return $this->belongsTo('App\User', 'gamemaster_id');
}
}
My try to make Eloquent, but that fails:
$result = Campaign::where('status', '=', 1)->with('gamemaster')->select('name')->orderBy('users.updated_at', 'desc')->get();
You can do it in two ways, first using the query builder,
$campaigns = DB::table('campaigns')->leftJoin('users', 'campaigns.gamemaster_id', '=', 'users.id')
->select(['campaigns.name as name', 'users.name as gamemaster_name'])
->where('campaigns.status', '=', 1)
->orderBy('users.updated_at', 'desc')
->get();
And with eager loading, you can get the campaigns like below. However, to sort by relation property, you need an another layer which is not that easy to implement.
$campaigns = Campaign::where('status', '=', 1)->with(['gamemaster' => function($query){
$query->select(['id', 'name']);
}]->select('id', 'gamemaster_id', 'name')->get();
But you can use collection functions to easily sort it (However, it will take more execution time)
$campaigns = Campaign::where('status', '=', 1)->with(['gamemaster' => function($query){
$query->select(['id', 'gamemaster_id', 'name', 'updated_at']);
}]->select('id', 'name')->get()->sortByDesc(function ($campaign) {
return $campaign->gamemaster->updated_at;
})
The following query should work:
Campaign::whereStatus(1)
->join('users', 'campaigns.gamemaster_id', '=', 'users.id')
->select('campaigns.name', 'users.name')
->orderBy('users.updated_at', 'desc')
->get()
School have books and students.
Book have pages.
How can i get all pages from all books where school_id = 1 ? I tried the code below, but i didn't worked.
Page::whereHas('book.school', function($query) {
$query->where('id', '=', 1);
})->get()->toJson();
Also, what if i'd like to get all pages from book_id = 1 and school_id = 1 ?
I need to use school_id here just to check if the book we are getting the pages is from the same school as the logged student.
Easy way, assuming Book belongsTo School:
Page::whereHas('book', function($query) {
$query->where('school_id', '=', 1);
})->get();
complete solution:
Page::whereHas('book', function($q) {
$q->whereHas('school', function ($q) {
$q->where('id', '=', 1);
});
})->get();