Eloquent Get Models based on fields in related tables - laravel

I have multiple Models related to my User model(eg: profiles, addresses, orders,...etc)
I want to get all the users that were updated in the past 24 hours, based on the update_at field in each of the related tables accordingly.
I have found the following if u have one related table, but in my case I have more than 3 tables that I need to check:
$users = User::with('orders')
->where('updated_at', $valueA)
->whereHas('orders', function($query)
{
$query->where('updated_at', $valueB);
})->get();
I hope someone can help me to know how to apply this for multiple where clauses n=on multiple related tables.

Try the below code,
$users = User::with(['profiles', 'addresses', 'orders'])
->whereDate('updated_at','>', $yesterdayDate)
->orWhereHas('orders', function($query) use ($yesterdayDate){
$query->whereDate('updated_at','>', $yesterdayDate);
})->orWhereHas('addresses', function($query) use ($yesterdayDate) {
$query->where('updated_at','>', $yesterdayDate);
})->orWhereHas('profiles', function($query) use ($yesterdayDate){
$query->where('updated_at','>', $yesterdayDate);
})->get();

If you have direct relation from users to all models like orders, profiles, addresses etc then you can try this.
$valueA = $time // whatever time you want
$users = User::
where('updated_at', $valueA)
->whereHas('orders', function($query) use ($valueA)
{
$query->where('updated_at', $valueA);
})
with('orders')
->whereHas('profiles', function($query) use ($valueA)
{
$query->where('updated_at', $valueA);
})
with('profiles')
->whereHas('addresses', function($query) use ($valueA)
{
$query->where('updated_at', $valueA);
})
with('addresses')
->get();
Thank you.

Related

query joins only last row from relationship

User can apply many times to single order. The last apply is the one I want. My code:
$users = User::whereHas('applies', function ($query) use ($order_id){
$query->where('order_id', $order_id);
})->with(['applies' => function($query) use ($order_id){
$query->orderBy('id', 'desc')->where('order_id', $order_id)->first();
}])->paginate($request->perPage);
This limit the number of applies only in the last user, the other applies records are empty. Removing first() from with() shows all applies in all users. How is that? Please help.
I've tried limit(1), take(1)->get(), take(1), but it also fails.
There is no simple way to limit eager loading.
You can use a HasOne relationship:
public function latestApply() {
return $this->hasOne(Apply::class)->orderBy('id', 'desc');
}
$users = User::whereHas('applies', function ($query) use ($order_id){
$query->where('order_id', $order_id);
})->with(['latestApply' => function($query) use ($order_id){
$query->where('order_id', $order_id);
}])->paginate($request->perPage);
This will still fetch all applies in the background, but only show the latest one for each user.
See also https://stackoverflow.com/a/50571322/4848587 for other possible solutions.

Eloquent: How to combine eager loading and filter by pivot?

I have a many-to-many relationship between models. For a given model instance, I know how to filter the related models according to the value of a pivot. For example, in the case of users and roles, I would use:
User->roles()->wherePivot('admin',1);
Similarly, I know how to eager load all roles for a set of users:
User::where('active',1)->with('roles')->get();
What I am trying to do is combine these two concepts. For example, how do I retrieve a set of users with their eagerly loaded roles, where the users are filtered according to a field on the pivot?
I realise I can do this easily enough with raw SQL, but I would prefer to use Eloquent if possible.
You can restrict your eager loaded relations using a closure.
$users = User::with(['roles' => function ($query) {
return $query->wherePivot('admin', 1);
}])
->where('active', 1)
->get();
You can also query relations using whereHas.
$users = User::with('roles')
->whereHas('roles', function ($query) {
return $query->wherePivot('admin', 1);
})
->where('active', 1)
->get();
Pass a closure in to with when eager loading to add clauses to the query:
User::with(['roles' => function ($query) {
$query->where('admin', 1);
}])->where('active', 1)->get();

Sort Users based on specific Value(string) in Laravel

I want to sort users based on the specific value. For example I have Users table and has relation with Profiles Table. In the Profiles table I have saved Country (string) of the user.
Now I want to sort specific country users first and then the other country Users.
Please guide me how can I do this in Laravel.
Thanks
You can play with that code.
$users = Users::with(['profiles' => function ($query) {
$query->where('country', 'USA');
$query->orWhere('country', 'Poland')
}])->get();
I have not check this but You may try this solution. It will help you.
$users = Users::with(['profiles' => function ($query) {
$query->orderBy("country='your country name'", 'DESC')
$query->orderBy('country', 'ASC')
}])->get();
You can use this
$users = Users::with(['profiles' => function ($query) use($country) {
$query->orderBy(DB::raw('case when country="'.$country.'" then 1 else 2 end'))->orderBy('country', 'ASC');
}])->get();

Order by related table column

I have a query like:
$users = User::with('role')
->get();
How can I order the results by the related table, so it's something like:
$users = User::with('role')
->orderBy('role.id', 'DESC')
->get();
Is there a way to do it without joining the role table (since we're already doing with('role')?
what are you trying to order. the list of users or the roles.
if you are trying to sort the users base on role do.
$users = User::with('role')->orderBy('role_id', 'DESC')
->get();
if you are trying to sort the roles of the user then pocho's answer is correct.
$users = User::with(array('role' => function($query)
{
$query->orderBy('id', 'DESC');
}))->get();
From the documentation:
$users = User::with(array('role' => function($query)
{
$query->orderBy('id', 'DESC');
}))->get();
You can also do a raw query using DB::raw like in the examples here.
You can always sort the returned collection quite easily...
$users = User::with('role')
->get()
->sortBy(function($user, $key)
{
return $user->role->id;
});
This is assuming a user hasOne or belongsTo a role. If your relationship is something that can return multiple roles, then it becomes a bit more complex because you need to decide which of the user's roles to sort by.

laravel search many to many Relashionship

I am testing eloquent for the first time and I want to see if it suit my application.
I have Product table:
id, name
and model:
class Produit extends Eloquent {
public function eavs()
{
return $this->belongsToMany('Eav')
->withPivot('value_int', 'value_varchar', 'value_date');
}
}
and eav table:
id, name, code, field_type
and pivot table:
product_id, eav_id, value_int, value_varchar, value_date
class Eav extends Eloquent {
public function produitTypes()
{
return $this->belongsToMany(
'ProduitType'
->withPivot('cs_attributs_produits_types_required');
}
All this is working.
But I want to search in that relashionship:
e.g: all product that have eav_id=3 and value_int=3
I have tested this:
$produits = Produit::with( array('eavs' => function($query)
{
$query->where('id', '3')->where('value_int', '3');
}))->get();
But I get all the product, and eav data only for these who have id=3 and value_int=3.
I want to get only the product that match this search...
Thank you
I know the question is very old. But added the answer that works in the latest versions of Laravel.
In Laravel 6.x+ versions you can use whereHas method.
So your query will look like this:
Produit::whereHas('eavs', function (Builder $query) {
// Query the pivot table
$query->where('eav_id', 3);
})->get()
My suggestion and something I like to follow is to start with what you know. In this case, we know the eav_id, so let's go from there.
$produits = Eav::find(3)->produits()->where('value_int', '3')->get();
Eager loading in this case isn't going to save you any performance because we are cutting down the 1+n query problem as described in the documentation because we are starting off with using find(). It's also going to be a lot easier to read and understand.
Using query builder for checking multiple eavs
$produits = DB::table('produits')
->join('eav_produit', 'eav_produit.produit_id', '=', 'produits.id')
->join('eavs', 'eavs.id', '=', 'eav_produit.eav_id')
->where(function($query)
{
$query->where('eav_produit.value_int','=','3');
$query->where('eavs.id', '=', '3');
})
->orWhere(function($query)
{
$query->where('eav_produit.value_int','=','1');
$query->where('eavs.id', '=', '1');
})
->select('produits.*')
->get();
Making it work with what you already have...
$produits = Produit::with( array('eavs' => function($query)
{
$query->where('id', '3')->where('value_int', '3');
$query->orWhere('id', '1')->where('value_int', '1');
}))->get();
foreach($produits as $produit)
{
if(!produit->eavs)
continue;
// Do stuff
}
From http://four.laravel.com/docs/eloquent:
When accessing the records for a model, you may wish to limit your results based on the existence of a relationship. For example, you wish to pull all blog posts that have at least one comment. To do so, you may use the has method
$posts = Post::has('comments')->get();
Using the "has()" method should give you an array with only products that have EAV that match your criteria.
$produits = Produit::with( array('eavs' => function($query)
{
$query->where('id', '3')->where('value_int', '3');
}))->has('eavs')->get();

Resources