How can I get the total number of records for each of the grouped column(some_id) results generated in this eloquent query? (Answers generated using DB query builder or vanilla PHP also welcome).
$results = \App\MyModel::groupBy('some_id')
->whereNotNull('some_id')
// some query here to get sum of each grouped column records
->get();
The desired result would be such that when I'm looping through the results, I can also have a field called for example totalRecords for each grouped results. i.e.
foreach($results as $result) {
echo $result->totalRecords;
}
$results = DB::table('your_table')
->select('some_column_name', DB::raw('count(some_id) as totalRecords'))
->whereRaw('some_id IS NOT NULL')
->groupBy('some_id')
->get();
You can do like this :-
$results = \App\MyModel::select('*', DB::raw('count(some_id) as totalRecords'))
->groupBy('some_id')
->whereNotNull('some_id')
->get();
foreach ($results as $result) {
echo $result->totalRecords;
}
Collection Provide itself count() method.
But sometime once you fetch whole collection using get(). You can use count method on collection something like this:
$results = \App\MyModel::groupBy('some_id')
->whereNotNull('some_id')
// some query here to get sum of each grouped column records
->get();
dd($results->count());
Also, If your data is not collection then Php array's provide you count method you can use that too:
dd(count($results));
I used dd method just for debuging purpose.That will show you result before actual output.
count() method of array will help you to count collection as well as sub collection or array of sub array.
Good luck !!!
Related
I have code like this
$tag = Tag::where('slug' = $slug)->first();
$posts = $tag->posts;
It works correctly but I want to use limit, orderBy, offset and other operation on posts. So it works
$posts = $tag->posts->where('accept', 1);
But it doesn't works
$posts-> $tag->posts->orderBy('created_at', 'desc');
//or
$posts-> $tag->posts
->offset($offset)
->limit($limit);
I must use offset and limit into query from var.
How I can do that?
When you set up your initial query Tag::where('slug' = $slug)->first(); you're using Query Builder and it's methods. But when Laravel returns the results, they're returned as a collction object -- those have very similar but slightly different methods available. https://laravel.com/docs/5.8/collections#available-methods
On a collection or its children, instead of orderBy() you would use sortBy() or sortByDesc(). Those will return an instance of the collection, sorted by your specified key. $results = $posts->sortBy($sorting);
The same idea with limit, in this case you can use the splice method. (Collections are basically php arrays on steroids) Splice accepts two parameters, a starting index and a limit. So, to get only the first 10 items, you could do this: $results = $posts->splice(0, 10);
And of course, you can also chain those togeather as $results = $tag->posts->sortBy('id')->splice(0, 10);
When you use child, Eloquent create another subquery, then result is added to parent, thats way its not sorting properly.
A solution could be join tables:
$tags = Tag::where('tags.slug' = $slug)
->join('tags', 'tag.post_id', '=', 'posts.id')
->orderBy('posts.created_at', 'desc')
->select('tags.*')
->get();
I have a table called gk and I am currently running two queries. Please have a look at the queries:
Gk::groupBy(DB::raw("MONTH(created_at)"))
->groupBy(DB::raw("YEAR(created_at)"))
->selectRaw('id, user_id, sum(ton) as ton,pl, count(id) as total, sum(w) , created_at')
->with(array('user'=> function($q){
$q->select('id', 'userName', 'profilePic');
}))
->where('user_id', $userData[0]->id)
->get();
This query returns a little summary of every months. As you can I see I am grouping results by months and years. And I have another query which will return all the rows of any given months.
I am running second query like this
$m=Carbon::parse($request->date);
Gk::where('user_id',$request->user_id)->whereRaw(DB::raw("YEAR(created_at)=$m->year"))->whereRaw(DB::raw("MONTH(created_at)=$m->month"))
->orderBy('created_at','desc')
->get();
The second query returns all the rows of any month. I'm executing this query in a foreach loop for all of the months that are returned in the first query.
I am trying to combine this two query into one so that I can get a group of the results by months and years and also all the details of that month.
Any help, suggestions or idea would be extremely helpful.
[Note: For the date in second query, this date is created_at result from the first query.]
Thank you.
The way I read your question is as following: The second query is executed in a loop with results from the first one. Is that right? In my answer I have explained a way to execute the second query just one time instead of in a loop. You'd still have to execute the first query once.
So, I think that you are better of using the Php collection methods:
$results = Gk::where('user_id',$request->user_id)
->orderBy('created_at','desc')
->get()
->groupBy(function (Gk $item) {
return $item->created_at->format('Y-m');
});
The groupBy method has to return an attribute on which you want to group the elements. For this example I think that using a yyyy-mm format will do fine.
Reference: https://laravel.com/docs/5.5/collections#method-groupby
Edit: Maybe you can also get rid of the orderBy method call because you are grouping by afterwards:
$results = Gk::where('user_id',$request->user_id)
->get()
->groupBy(function (Gk $item) {
return $item->created_at->format('Y-m');
});
Edit 2: To combine the information of the two queries, you could do something like the following:
$results = Gk::where('user_id',$request->user_id)
->get()
->groupBy(function (Gk $item) {
return $item->created_at->format('Y-m');
})->map(function(Collection $rows) {
return [
'sum(ton)' => $rows->sum('ton'),
'total' => $rows->count(),
'sum(w)' => $rows->sum('w'),
'rows' => $rows
];
);
Note that I have omitted a few of the selected columns in your first query because they are not unique in the given group by. But feel free to add any logic in the map function. Because we use map() after groupBy, every call of map() will receive a collection of items for one month. You can that use that fabulous collection magic to calculate all values that you need and reduce the number of queries to just one.
I'm having a problem getting some datas from my database via eloquent:
at first I do this to get 'id' and 'capMax' from clase_schedule table:
$plazas = DB::table('clase_schedule')->select(['schedule_id', DB::raw('SUM(capMax) as capMax')])->groupBy('schedule_id')->get();
and then i want to get the the name of table schedule where the id i got before coincides with the one on this table, like this:
$nom_horarios = DB::table('schedule')->select('name')->where('id', 'in', $plazas->schedule_id)->get();
I get this error:
"Trying to get property of non-object"
Since, $plazas is an array so you should loop the $plazas to get the value in next query as below :
foreach ($plazas as $plaza)
{
$nom_horarios[] = DB::table('schedule')->select('name')->where('id', 'in',$plaza->schedule_id)->get();
}
print_r($nom_horarios);
$plazas returns an array of items, instead of get(), use first(). This will return single item.
$plazas = DB::table('clase_schedule')->select(['schedule_id', DB::raw('SUM(capMax) as capMax')])->groupBy('schedule_id')->first();
Or loop plazas in foreach
What is returning in the $plazas variable?
I think the problem is you are getting a collection and not a item... If you want to get just one plaza you should ->first() instead of ->get();
when i try to paginate results passed from the logged in user I get the error:
$message = Auth::user()->Notifications()->orderBy('created_at', 'desc')->get()
->groupBy(function($date) {
return Carbon::parse($date->created_at)->format('M d'); // grouping by day
})
->paginate(2);
Call to undefined method Illuminate\Database\Eloquent\Collection::paginate()
what is the problem and how can I paginate my object array?
Try this:
$message = Auth::user()->Notifications()->orderBy('created_at', 'desc')
->groupBy(function($date) {
return Carbon::parse($date->created_at)->format('M d'); // grouping by day
})->paginate(2);
the paginate method needs to be the last element in the chain like->get()
// edit: As stated here: http://laravel.com/docs/4.2/pagination
Note: Currently, pagination operations that use a groupBy statement cannot be executed efficiently by Laravel. If you need to use a groupBy with a paginated result set, it is recommended that you query the database manually and use Paginator::make.
This could also be helpful: http://www.jenssegers.be/blog/57/laravel-pagination-with-grouping-and-eager-loading
Of course you get the error as groupBy returns an instance of Illuminate\Support\Collection. You would need to do something like
$messages = Auth::user()->Notifications()->orderBy('created_at', 'desc')->paginate(2);
$messages->setItems($messages->groupBy(function($date) {
return $date->created_at->format('M d'); // grouping by day
}));
This way you set up new items in your pagination object which are grouped results from database.
I'm new to Laravel and i need your help please.
This runs on my controller and the result should be "3" as long as I have 3 rows with that title in the same table.
$countcategories = DB::table('categories')
->select(DB::raw('count(title) as result'))
->where('title','=','dsds')
->get();
I'm passing the query result to the view like this->with('counts', $countcategories)
And now my questions are:
In the view I can only display the result by using foreach. Why? My query returns only one row.
I want to store the query result in a variable inside my controller in order to use that result. How can I do that?
Thank you very much!
you should use ->first() method:
$countcategories = DB::table('categories')
->select(DB::raw('count(title) as result'))
->where('title','=','dsds')
->first();
What you are getting are rows from a result, it tunrs out there is only one in your situation.
You have already done that.
Anyways, here's my approach:
// The result
$categories = Category::where('title','=','dsds');
foreach( $categories->all() as $category ) {
echo $category->title . "\n";
}
// The count
echo $categories->count();