laravel Eloquent query WhereHas wrong result - laravel

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

Related

Nested eager loading dynamically created in a constrain

songs table
id version number
1 AAA 1
2 BBB 1
3 CCC 1
4 DDD 2
5 EEE 3
6 FFF 4
7 GGG 4
The objective is to obtain, for example, all songs that have the same number as the song with id 1 (songs with ids 1, 2 e 3)
Song model
public function songs()
{
return $this->hasMany(Song::class, 'id_hierarchy');
}
Query: it doesn't work it's just for demonstration (there is no sameNumber model)
public function readSongsVersions()
{
$data = Hierarchy::query()
->whereNull('parent_id')
->with([
'children.songs'
'children.songs.sameNumber'
])
->get();
}
There is no sameNumber model.
Theoretically, a relationship would have to be created in the model song and it would be a relationship with the model song itself; Is such a solution possible?
The solution will eventually go through a constraint.
$data = Hierarchy::query()
->whereNull('parent_id')
->with([
'children.songs'
'children.songs' => function ($query) {
$query->where('number', '=', function($query) {
$query->select(DB::raw('i.number)'))
->from('songs as i')
->whereRaw('i.number = songs.number')
});
},
])
->get();
}
How to nest in eager loading the result of the subquery ( 'children.songs' => function ($query) {...}) to get the sameNumber music collection for each song;
the equivalent of: 'children.songs.sameNumber'
You can create relationships, that references itself. A where statement to ensure, not the same row is returned, since you are relying on the number column.
In Song.php
public function sameNumber()
{
return $this->hasMany(Song::class, 'number', 'songs.number')
->whereColumn('version', '!=', 'songs.version');
}
There is one part you have to figure out, but when you run the code it should be fairly obvious, 'version' and 'number' columns are gonna be ambiguous and you have to check what naming Laravel uses, when dealing with tables named the same. Change the code like so songs2.version, dependent on the naming. You can also always call ->toSql() on the relationships to see the SQL query.

How to retrieve data from two table in Laravel Eloquent

I have two DB tables.
education_institutions
id institution_name country city logo description
1 ABC College UK London null null
user_educations
id user_id institution_id grade year
1 1 1 3.2 2010
Relationships with both models are
UserEducation
public function educationInstitution()
{
return $this->hasMany(EducationInstitution::class,'institution_id');
}
EducationInstitution
public function userEducation()
{
return $this->belongsTo(UserEducation::class,'institution_id');
}
Now how can I retrieve all education institutions of a particular user with the institution details from educations_institution table.
I tried something like
public function getUserEducation()
{
$userEducation = auth()->user()->userEducation()
->orderBy('created_at', 'desc')
->get();
return response()->json([
'userEducation' => $userEducation
]);
}
But it retrieves only education institution id like:
I need user educations with corresponding institution details.
You can use with() function for relationship selection.
public function getUserEducation()
{
$userEducation = UserEducation::with('educationInstitution')->where('user_id',auth()->user()->id)
->orderBy('created_at', 'desc')
->get();
return response()->json([
'userEducation' => $userEducation
]);
}

laravel Eloquent Relationship query with whereHas

I have two tables as bellow
user:
id
name
email
1
abc
abc#...
2
xyz
xyz#...
3
abx
abx#...
books:
id
user_name
book
price
1
abc:x1
book1
10
2
xyz:x2
book1
20
3
abc:x5
book3
30
4
ab:x2
book1
10
If you notice that my 2nd table field user_name have user_name of user table plus :x and number
maybe this didn't make sense but this is my project requirements
Now when I want to query some user with books like If I search a user with ID (1)
it should give me records of 1 & 3 because of user_name
I tried this
$user = USER::with('books')
whereHas('books', function ($query) {
$query->where('user_name', 'like', 'name:%');
})->get();
Also, I tried this
USER::with('books')
->whereHas('books', function ($query) use ($name) {
$query->where('user_name', 'like', $name . ':%');
})
Also not working.
Also how to get 3rd extra column value after :x
Also, is this possible to write this query in model?
Thanks
I would suggest you that you should always store normalized data in database irrespective of the presentation layer of the data. The data can be transformed in your desired form at query level or in the app itself.
So you should introduce 2 columns in your books table
user_id
sequence
like
id
user_id
sequence
book
price
1
1
1
book1
10
2
2
2
book1
20
3
1
5
book3
30
4
3
2
book1
10
This way you can filter out the users easily and you can apply filter on user books also. To construct the user name you can use accessor and a virtual attribute in your book model which will construct the user name for you like
class Book extends Model
{
protected $appends = ['user_name'];
protected $with = ['user'];
public function getUserNameAttribute()
{
return $this->user->name .":x". $this->sequence;
}
public function user()
{
return $this->belongsTo(User::class, 'id', 'user_id');
}
}
$appends will hold the custom attributes for your models and the accessor method will construct a user name using the user() relation. So its important if you load books then you should also eager the related users so that in accessor $this->user->name will have the name from user table otherwise it will be empty, For this you can use $with property in your model which will intimate that related user should be loaded whenever books are loaded.
Now you can get the user with specific id as
User::with('books')->find(1);
Or books by the name of user as
Book::whereHas('user', function ($query) use ($name) {
$query->where('name', 'like', $name);
});
Or books by the name of user and with the number after x that is sequence
Book::whereHas('user', function ($query) use ($name, $sequence) {
$query->where('name', 'like', $name);
})->where('sequence', $sequence);

Laravel 5.2 Eloquent ORM to get data from 3 tables

I have the following tables. users, user_details and client_teams. Each user has one details and each user can have many teams. schema for users:
id, name, email,parent_user_id
user_details:
id, user_id, client_team_id
client_teams:
id, user_id, team_name,status
In user_model i have the following relations:
public function userDetails(){
return $this->belongsTo('App\Models\UserDetails','id','user_id');
}
public function clientTeamList(){
return $this->hasMany('App\Models\ClientTeams','user_id','id');
}
In user_details model i have the following relation:
public function clientMemberTeam(){
return $this->belongsTo('App\Models\ClientTeams','client_team_id');
}
I want to be show the list of users who have a specific team ID and created by a specific user. The query that i am using is this:
$userCollections=Users::where([
['users.status','!=','DELETE'],
['users.parent_user_id',$clientId],
['users.id','!=',$loginUser->id]
])
->with([
'userDetails'=>function($query) {
$query->where('client_team_id',1);
}
]);
This is giving me all records for this user, Whereas i want to match by client_team_id and user_id
You need to use whereHas and orWhereHas methods to put "where" conditions on your has queries.
Please look into https://laravel.com/docs/8.x/eloquent-relationships
$userCollections = Users::where([['users.status', '!=', 'DELETE'],
['users.parent_user_id', $clientId],['users.id', '!=', $loginUser->id]
])
->whereHas('userDetails' => function ($query) {
$query->where('client_team_id', 1);
})->get();

Laravel select posts and comments for active users only

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);
});
}])

Resources