Using Spatie Query Builder I would like to extend the filters on nested relationships
The following code fetches locations with the relation jobs counts which works fine. I would like to extend the filter on job relation to can query relation job.level which is a many to many. How would I go for?
the filter would look like /options/?filter[job.level]=2
Germany - 12,
Italy - 34
$locations = QueryBuilder::for(JobLocation::class)
->select('id as value', 'title', 'country_id')
->orderBy('title')
->withCount(['job as counts' => function ($q) {
$q->whereNull('deleted_at');
}])
->whereHas('country', function ($q) {
$q->where('id', '=', 80);
})
->allowedAppends(
'job',
)
->allowedIncludes('job', 'job.level',)
->allowedFilters([
AllowedFilter::exact('job.language_id'),
AllowedFilter::exact('job.level', 'job.level.id')
])->get();
I think you are looking for the whereHas function. See the docs for querying relation existence here. But you are already doing this for the country relationship, this is not any different.
So I think yours would look something like:
$locations = QueryBuilder::for(JobLocation::class)
->select('id as value', 'title', 'country_id')
->orderBy('title')
->withCount(['job as counts' => function ($q) {
$q->whereNull('deleted_at');
}])
->whereHas('country', function ($q) {
$q->where('id', '=', 80);
})
//New query constraint here
->whereHas('job', function ($q) {
$q->where('level', '=', 2);
})
->allowedAppends(
'job',
)
->allowedIncludes('job', 'job.level',)
->allowedFilters([
AllowedFilter::exact('job.language_id'),
AllowedFilter::exact('job.level', 'job.level.id')
])->get();
Related
I have 3 tables products, prices, cats.
I need to filter product by cats and sort by price but I have a problem:
this code work very well but needs pagination.
$products = Product::with('photo', 'price', 'brand')
->whereHas('cats', function ($q) use ($cat) {
$q->where('cat_id', $cat->id);
})
->get()
->sortByDesc(function($query) {
return $query->price->price;
});
at first I did it like this:
$products = Product::with('photo', 'price', 'brand')
->whereHas('cats', function ($q) use ($cat) {
$q->where('cat_id', $cat->id);
})
->paginate($page)
->sortByDesc(function ($query) {
return $query->price->price;
});
but links() did not work.
After i did it like this:
$products = Product::with('photo', 'price', 'brand')
->whereHas('cats', function ($q) use ($cat){
$q->where('cat_id', $cat->id);
})
->paginate($page);
$products->setCollection(
$products->sortBy(function ($query) {
return $query->price->id;
})
);
but sortBy does not work.
so I can't use orderBy() by join prices table
because when I do it I can show all products and I can't filter product by categories
my mind does not work, if someone can to help me, I will be very grateful
I believe you can also do:
Product::join('price', 'price.id', '=', 'photo.price_id')
->orderBy('price.price', 'asc')
->select('photo.*')
->paginate(10);
How can I select on whereHas() some columns in relation.
My current query looks like as it follows
Location::select(['title'])
->withCount(['job' => function($q) {
return $q->where('language_id', 1)->whereNull('deleted_at');
}])->whereHas('country', function ($q) {
return $q->where('id', '=', 80);
})->get();
and I tried
Location::select(['title', 'id as value'])->withCount(['job' => function($q) {
return $q->where('language_id', 1)->whereNull('deleted_at');
}])->whereHas('country', function ($q) {
return $q->select('title', 'iso3')->where('id', '=', 80);
})->get();
but nothing is getting returned on country relation. How do I refactor this query to get it work?
whereHas() doesn't eager load the relation, only filters results based on it. To eager load, use with().
Location::with('country:id,title,iso3')
->select(['title', 'id as value', 'country_id'])
->withCount(['job' => function($q) {
$q->where('language_id', 1)->whereNull('deleted_at');
}])
->whereHas('country', function ($q) {
$q->where('id', '=', 80);
})->get();
I have a tournament table.
Each tournament hasMany Championships.
I want to get the tournament that match the championshipID = 333.
So, I do it :
$tournament = Tournament::with([
'championships' => function ($query) use ($request) {
$query->where('id', '=', 333);
},
'championships.settings',
'championships.category',
'championships.tree.user1',
'championships.tree.user2',
'championships.tree.user3',
'championships.tree.user4',
'championships.tree.user5'
])->first();
Example of 1 of my relations:
public function settings()
{
return $this->hasOne(ChampionshipSettings::class);
}
Tell me if you need all, to post it.
But as I put 1 eager loading relationship, I get all my tournaments instead of getting just one.
What Am I missing???
I think you're looking for whereHas() which will allow you to filter a model based on a related model's constraints. You should also use a subquery for the nested constraints if you're getting the related model more than once to avoid query duplication like:
$tournament = Tournament::whereHas('championships', function($query) use ($championshipId) {
return $query->where('id', $championshipId);
})
->with(['championships' => function ($query) use ($request) {
$query->where('id', '=', 333)
->with([
'settings',
'category',
'tree' => function($query) {
return $query->with('user1', 'user2', 'user3', 'user4', 'user5');
}]);
}])
->first();
Hi i have a categories and products table with one to many relation. I want to select categories with products which are in product_ids(which it will get from other query). I tried
$categories = Category::with(['products' => function ($query) use($product_ids) {
$query->whereIn('id', $product_ids);
}])
->get();
the above query will select all the categories even if the product not in product_ids ( empty array if not in produc_id) but i just want to select those categories which has the products in the product_ids.please help
I just Solved it by adding whereHas
$categories = Category::with(['products' => function ($query) use($product_ids) {
$query->whereIn('id', $product_ids);
}])
->whereHas('products', function ($q) use($product_ids) {
$q->whereIn('id', $product_ids);
})
->get();
Use whereHas
$categories = Category::whereHas('products', function ($query) use($product_ids) {
$query->whereIn('id', $product_ids);
})
->get();
(laravel 4.2)
There are four tables involved; users, posts, flags, and post_flags.
I want to retrieve every post a certain user has, and retrieve the flags set for the post, but only the flags that are set by the user in question.
For example: A post can have flags: 1,2,2,3 where flag 2 is set twice. Once by User A, once by User B. I don't want to see the flags that User B has set.
The Eloquent query in my controller:
$posts = Post::whereHas('companies', function($q) use($company_id) {
$q->where('id', '=', $company_id);
})->with('flags')->get();
The Relation in my Post model:
public function flags() {
return $this->belongsToMany('PostFlag', 'post_postflags', 'post_id', 'flag_id')
->withTimestamps()->withPivot('owner');
}
How would I achieve this using Eloquent ORM?
UPDATE
My final query, thanks to andrewtweber:
Final query
$posts = Post::whereHas('users', function($q) use($id) {
$q->where('id', '=', $id);
})->get()->load([
'flags' => function($query) use($id) {
$query->where('owner', '=', $id)->orWhere('owner', '=', 'SYSTEM');
}
]);
Use wherePivot
http://laravel.com/api/4.2/Illuminate/Database/Eloquent/Relations/MorphToMany.html
$flags = $post->flags()
->wherePivot('user_id', '=', $user_id)
->get();
Or with eager loading
$posts->load([
'flags' => function ($query) use($user_id) {
$query->wherePivot('user_id', '=', $user_id);
}
]);