Say I have this 3 tables Blog, Post, Comment which has corresponding models Blog, Post, Comment.
No here is the relation between them:
Blog has many Post, posts()
Post belongs to Blog, blog()
Post has many Comment, comments()
Comment belongs to Post post()
Now I want to execute some query like this:
Blog::with(array('posts.comments' => function($q)
{
//query Post columns
})->find(1);
As I know the $q is corresponding to the Comment table. Is there any way to query the Post table?
Query nested relation like this:
$blog = Blog::with(['posts' => function ($q) {
$q->where('column','value'); // query posts table
}, 'posts.comments' => function ($q) {
$q->where('commentsColumn','anotherValue'); // query comments table
}])->find(1);
Eloquent will load posts accordingly, only then will it fetch the comments for those posts.
Related
I am trying to get a query with Laravel eloquent. I have a table posts which has a morph relationship column author. This author column can refer to a users table or admins table. So this is the way I am getting the author of each posts:
$query = Post::with(['author']);
Now, there's another table I want to include if the author is a user, which is address. The problem is, there's no address relationship in admin table.
So, when I try to do this,
$query = Post::with([
'author' => function ($q) {
$q->with('address');
}
]);
It throws me Illuminate\Database\Eloquent\RelationNotFoundException exception as the relation address is not defined for admin.
How do I solve this problem? I want fetch all the posts with author and include address in the authors that has an address
You can solve that by using the whereHas combine with whereDoesntHave to include both Author who has address and who doesn't have
$query = Post::with([
'author' => function ($q) {
$q->whereHas('address');
$q->orWhereDoesntHave('address');
}
]);
It you only whereHas without orWhereDoesntHave it will return only post which has author with existing address and not author which doesn't have address so to eager load both who has and who hasn't you include both wherHas and orWhereDoesntHave
whereDoesntHave
whereHas
orWhereDoesntHave
In laravel 8, I am filtering blog articles by category. However when I select multiple categories in my select menu. I do get the proper request . for example: articles/category/?category_ids=3,4
But it will only output one selected filter. If I select 2 filters it just selects that next filter as if I only selected that one. (I also use Axios but the request is done proper, so its in my Controller)
Here is my code I tried:
$data['articles'] = Article::whereHas('categories', function ($query) use($category_ids){
$query->whereHas('category_id', '=', $category_ids)->where('premium',0);
;})->get();
I also tried:
$data['articles'] = Article::whereHas('categories', function ($query) use($category_ids){
$query->whereIn('category_id', [$category_ids])->where('premium',0);
;})->get();
So how do I get to query both or more category id's ?
I am using a pivot table:
Articles can have many Categories
Categories can have many Articles
I use article_category as a pivot table
When checking for relationship existence in many-to-many relations, the check is still to be done against the id in the categories table.
Try this
$category_ids = collect(explode(',', $request->category_ids))
->map(fn($i) => trim($i))
->all();
$data['articles'] => Article::whereHas('category', fn($query) =>
$query->whereIn('categories.id', $category_ids)
->where('categories.premium', 0)
)->get();
You can explode the categories and then make the query like this.
$categories = explode(',',$request->categories);
$data['articles'] = Article::whereHas('categories', function ($query) use($categories){
$query->whereIn('category_id', $categories)->where('premium',0);
})->get();
In my application, I have a posts table, categories tables and category_post table as a post and category have a many to many relationship.
I want to get all posts with their attached categories, but also group them together as on my frontend I want to be a loop over an object and show a list like this,
Cooking
Post Number 1
Post Number 3
Post Number 4
Music
Post Number 2
Post Number 5
Languages
Post Number 6
Post Number 7
I know in my controller I can do this,
$posts = Post::with('categories')->get();
But I don't how to groupBy a relational attribute or if I can structure the returned data in such a way that I can loop over it to form the list below.
you can get the data from db and then group them the way you want:
$posts = Post::with('categories')->get();
$result = $posts->groupBy([
'categories',
function ($item) {
return $item['category_name'];
},
], $preserveKeys = true);
more details about grouping by relation fields in:
https://laravel.com/docs/7.x/collections#method-groupby
As per given your table: posts and categories tables are the main tables and category_post table is a pivot table which contains the relation between posts and categories table :
So, Your relation should be posts->category_post->categories
$posts = Posts::with('category_post')->get();
$grouped = $posts->groupBy('category_post.category_id');
The category_post also related to the categories table for categories data.
In category model you cam setup and belongsToMany relation like the following
function posts()
{
return $this->beongsToMany(Post::class, 'category_post', 'category_id', 'post_id');
}
Then do as Arun A S suggested.
Can normally figure these relationships out but stumped on this one.
I have a basic blog platform that allows user to sign up and post blog posts.
Users can also follow other users.
I am trying to make a view where I can see all of the blog posts by the authors that I follow
I have the normal users table, and then a blog posts table which contains the user_id of the creator.
For followers, I then have a pivot table called followers which has user_id and follower_id.
This is my basic line to get all posts:
$posts = Post::orderBy('created_at', 'DESC')->get();
How can I change that so it only shows the posts where there post user_id is a field that matches in the followers table?
Thanks.
You may try something like this:
App\User Model:
public function favoriteAuthors()
{
return $this->belongsToMany(
User::class, // as Author
'followers', // pivot table
'follower_id', // as follower_id
'user_id', // as author_id
);
}
public function posts()
{
return $this
->hasMany(Post::class, 'user_id', 'id')
->orderBy('created_at', 'DESC');
}
Then load all posts of your favorite authors:
$posts = User::with('favoriteAuthors.posts')->find(auth()->user()->id);
Also you can use something like this:
if($me = auth()->user()) {
$me->load(['favoriteAuthors.posts']);
}
Now the $me will contain users that you follw and each users will contain their posts.
I have 3 Models... Category, Post, Vote
When viewing a category, I am showing an index of all Posts in that category. So I'm doing something like foreach ($category->posts as $post) in my view.
The question I have now is how can I order the posts based on the sum of votes they have?
I have standard relationships setup, so that a post hasMany votes.
You can do it either by defining a helper relation on the Post model and sorting the collection after the relation is loaded OR simply by joining the votes and ordering in the query.
1 RELATION
// Post model
public function votesSum()
{
return $this->hasOne('Vote')->selectRaw('post_id, sum(votes) as aggregate')->groupBy('post_id');
}
// then
$category->posts->load('votesSum'); // load relation on the collection
$category->posts->sortByDesc(function ($post) {
return $post->votesSum->aggregate;
});
// access votes sum like this:
$category->posts->first()->votesSum->aggregate;
2 JOIN
$category->load(['posts' => function ($q) {
$q->leftJoin('votes', 'votes.post_id', '=', 'posts.id')
->selectRaw('posts.*, sum(votes.votes) as votesSum')
->groupBy('posts.id')
->orderBy('votesSum', 'desc');
}]);
// then access votes sum:
$category->posts->first()->votesSum;
You can use scope for that:
// Post model
public function scopeOrderByVotes($query)
{
$query->leftJoin('comments','comments.post_id','=','posts.id')
->selectRaw('posts.*,sum(comments.id) as commentsSum')
->groupBy('posts.id')
->orderBy('commentsSum','desc');
}
// then
$category = Category::with(['posts' => function ($q) {
$q->orderByVotes();
}])->whereSlug($slug)->firstOrFail();