Laravel 5.2 Display each users posts they've made this week as count - php

I'm trying to display a list of all the users and how many posts they've each made this week, and how many they've made last week, inside of a form
I've used a hasMany relation between the two tables and the relationship it's self is working.
return $this->hasMany('App\applications', 'user_id');
inside of the view what I have that's displaying the post count is
{{$user->applications->count()}}
The main thing I'm stuck on is the SQL Query or using Carbon inside of the controller function to achieve this.
If anyone has done this before your help would be greatly appreciated!
Thank you.

Since you want to count posts for many users, eager load the data and use withCount():
User::withCount(['applications' => function($q) {
$q->whereBetween('created_at', [Carbon::now()->startOfWeek(), Carbon::now()]);
}])->get();
If you want to count the number of results from a relationship without actually loading them you may use the withCount method, which will place a {relation}_count column on your resulting models.
https://laravel.com/docs/5.4/eloquent-relationships#counting-related-models

Related

GroupBy data with a specific column using Laravel 8 [duplicate]

My goal is to retrieve all of a user's 'items' and display then in my view grouped by their 'status'. There are 4 possible statuses, each with their own <div> on the page containing the items' info. After some poking around I believe I need to use the groupBy() method like so:
$items = Item::ownedBy( Auth::id() )->groupBy('status')->get();
This does seem to do some sort of grouping, but when I iterate over the collection I get a max of 4 results, one for each status. This doesn't really solve my problem as I need to display all of a user's items for each status, not just one. I must be missing something here, I'd really like to avoid making a query for each status and displaying them that way. I suppose I could filter the collection by status and create 4 new collections, but isn't this what groupBy() is supposed to do?
You can do that very easy with laravel and Collections. Collections have powerful API and a lot of handy methods, to easily achieve what you want.
Your mistake here is that you are calling groupBy on the QueryBuilder object which returns only groupped by records from the database. Instead you must select all of the records you need, then they will be returned as a collection. After that you can manipulate the collection as you wish. So what you need is:
$items = Item::ownedBy( Auth::id() )->get()->groupBy('status');
You can view all of the Colletion class useful methods here.

Laravel paginate belongsToMany relationship?

I would like to paginate my results I get from my relationship. I have a products table/controller, a users table/controller and a markedProducts table. However, I don't have a markedProducts table because I don't actually need it. I use this solution to get all marked products of one user in my user model:
public function markedProducts(){
return $this->belongsToMany('App\Product', 'products_marks');
}
My question now is how can I paginate my results and my second question is how can I get the created_at value of each row in my markedProducts table?
Because my solution is only returning the marked products. However, I would like to show the user when he has marked the product.
So far I had this idea:
$markedProducts = DB::table('products_marks')->where('user_id', Auth::id())->orderBy('created_at', 'desc')->paginate(2);
$products = Product::whereIn('id', $markedProducts->lists('product_id'));
However, ->lists() is not a method anymore and I actually don't want to bypass the Laravel methods and I don't want to loop through my pagination to get an array with all product_id's.
Do you guys have any good and performant solution?
Kind regards and thank you!
Auth::user() will return the authenticated user.
And use relationship method markedProducts() to get the query of products.
And then orderBy the column created_at of pivot table.
At last, apply paginate to this eloquent builder.
Auth::user()->markedProducts()->orderBy('products_marks.created_at', 'DESC')->paginate($limit);

Eager loading with constraints generates too many queries. How can I alleviate that?

I have 4 tables that are related in the database and in models as follows:
Users (hasMany(communities), hasMany(comments), hasMany(submissions))
Communities (belongsTo(user), hasMany(submissions))
Submissions (belongsTo(community), belongsTo(user), hasMany(comments))
Comments (belongsTo(user) , belongsTo(submission))
Now. If I use the relations to get, say the 25 latest submissions, like this:
$submissions = Submission::simplePaginate(25);
I'm met with 76 queries run, after using foreach to loop through the results.
If I use eager loading with the following
$submissions = Submission::with(['user', 'community', 'comments'])->simplePaginate(25);
I'm met with 4 queries which is optimal (I think).
Now, my problem is that, on communities, I have a database field called active which accepts a 1 for an active community, and a 0 for an inactive. As you might have guessed, the previous query returns everything, including inactive communities.
I thought about eager loading constraints, so I used the following:
$submissions = Submission::with([
'community' => function($query) {
$query->active();
}
]
)->with(['user', 'comments'])->simplePaginate(25);
This still does that job with 4 queries, but now I run into another problem. This method filters the inactive communities, but still loads the posts, users and comments. And now I'm left with a result where I get posts from inactive communities.
Finally, I tried, upon reading this community, the following:
$submissions = Submission::whereHas(
'community', function($query) {
$query->active();
}
)->with(['user', 'comments'])->simplePaginate(20);
So, instead of using ->with() I used ->whereHas() as someone suggested. However, while this produces the correct results, i.e. it gives me posts, comments and users from the active communities only, it now does that in 23 queries, as per the feedback I get from Laravel Debugbar.
Is this normal? Is this the only way I can do this through Eloquent and without writing custom queries with joins? Am I blowing 23 queries out of proportion?
Any help would be greatly appreciated.
Your problem is that the active() scope is running a query for every community you are retrieving, in your case 20.
To optimize this you could make a specific relation in the Submission model where you filter the active communities proactively.
// Submission model
public function activeCommunities (){
return $this->hasMany(Community::class)->whereActive(true);
}
Now your query would look like:
$submissions = Submission::with(['user', 'comments', 'activeCommunities])
->simplePaginate(25);
This should perform 4 queries I believe.
Hope this helps you.
So, after tinkering with it for a while, I found a solution, but I'm still not sure. I'm posting this for future reference, since it solved my problem. The code I used is the following
$submissions = Submission::whereHas(
'community', function($query) {
$query->where('is_active', true);
}
)->with(['user', 'community'])->withCount('comments')
->paginate(25);
So, I tried using whereHas() to check for the models existence before actually eager loading the community model, if that makes sense? It seems to get me the results I want, since I now execute a total of 4 queries to get all the submissions, and the related info, filtering the inactive communities.

Laravel n+ issue eager loading count()

I'm going through my laravel application and trying to fix any n+ issues I can find. I have come across one scenario which isn't really an n+ but not sure what to call it.
I have 2 models Post, Comment. A post has many comments and a comment belongs to a post
When I loop through all my posts I would like to display a count of how many comments they contain. I've been able to do this fine. But the problem it is 2 queries.
How do I update the following Eloquent query to add a column for comments count.
Post::where('status', 1)->get();
Thanks
Update
As of Laravel 5.2.32, a new method was added to the query builder to help with this. When you add the withCount($relation) method to your query, it will add a {relation}_count field to the results, which contains the count of the supplied relation.
So, your query would be:
$posts = Post::where('status', 1)->withCount('comments')->get();
foreach($posts as $post) {
echo $post->comments_count;
}
You can read more in the documentation here.
Original
#JarekTkaczyk has a good blog post that does what you're looking for. Check out the article here.
Basically, you'll be creating a relationship that contains the count of comments for the post, and you'll eager load the relationship (thus avoiding the n+1). He also has some syntactic sugar in there for accessing the count through an attribute accessor.
Either just use count on the relationship, or if you think it's necessary, you could add a 'num_comments' to the Post model and increment it on the creation of a comment:
$post->comments()->count();
or in the comments model:
public function create( $commentData ){
$result = $this->fill( $commentData );
$this->post()->increment('num_comments');
return $result;
}

Laravel 4 Conditional Relationship

I need to be able to specify conditions on a relationship (one-to-many).
Example being; We have a Post which has many Comments, but I only want the Posts with Comments made by User A and then return the Post object(s).
The only way I can currently think of doing this is with a Fluent query, which wouldn't return the Post object I desire!
EDIT:
The comment has to of been made by User A. The relationship of the User who made the Comment to Post isn't a direct one. It would go through the Comment table.
RE EDIT:
Would it also be possible to say have distinct Posts? Rather than return 3 of the same Post Object?
You can query relationships. You would end up with something like this:
$postsWithComments = $user->posts()->has('comments', '>=', 1)->get();
Here is an extract from documentation: http://laravel.com/docs/eloquent
Querying Relations
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:
Checking Relations When Selecting
$posts = Post::has('comments')->get();
You may also specify an operator and a count:
$posts = Post::has('comments', '>=', 3)->get();

Categories