I am trying to assemble a graph of tasks per user/day, but I can't find how to order it easily.
I make the following queries to collect the tasks;
$tasksLastMonth = Task::where('user_id', Auth::user()->id)
->whereMonth('date', Carbon::now()->month)
->with('client')->get();
$tasksLastWeek = Task::where('user_id', Auth::user()->id)
->where('date', [Carbon::now()->startOfWeek(), Carbon::now()->endOfWeek()])
->with('client')->get();
On the other hand, I have two arrays with the days of the week and the month for the Xaxis of graph (are 2 graphs, one for week, and other for month)
$weekDays // [7,8,9,10,11,12,13]
$week // [1,2,3,4,.....,28]
Now, I need two arrays of the same length as the days of the week and month, for the Y axis, containing the number of tasks for each day. For example, if on day 8 there are 5 tasks it would look something like this:
$tasksInWeek = [0,5,0,0,0,0,0];
I also need other arrays for the number of clients for each day, but only the different ones. If one day there are 2 tasks for the same client, I only have to add 1 client that day.
I may be able to do it with just the query, but I can't find a way.
This should work:
$groupedTasks = Task::where('user_id', Auth::user()->id)
->whereMonth('date', Carbon::now()->month)
->with('client')
->get()
->groupBy(function ($item) {
return $item->date->format('Y-m-d');
})
->map(function ($items, $date) {
return $items->unique('user_id');
});
The idea here is to, first, group the elements by the date (instead of using an integer) and then, on each group just keep the distinct users.
You can duplicate almost the same logic to get the data for the weekly chart.
Related
Hello and thank you beforehand for your help.
I've been hitting my head against a wall with this problem for a few days now so decided to ask here. I have two queries in Laravel, one grouping totals by week, and the other by month. The week one works fine but for some reason the month one doesn't, the only difference in essentially the query is that the weekly one is calculated yearly but in a different period (starting in week 48 of last year and ending in week 47 of this year), while the monthly is just the real year. The only other difference is that the week query is inside an if to show the right thata in those final weeks of the year.
$weeklySalesLastYear = Invoice::where(function ($query) use ($year, $client_ids){
$query->where('year', $year-2)->where('week', '>=', 48)->whereIn('client_id', $client_ids);
})->orWhere(function($query) use ($year, $client_ids){
$query->where('year', $year-1)->where('week', '<=', 47)->whereIn('client_id', $client_ids);
})->groupBy('week')->selectRaw('sum(total) as total, week')->get();
That is my weekly query which works perfectly.
$sortedMonthlySalesLastYear = DB::table('invoices')
->where('year', $year-1)->whereIn('client_id', $client_ids)
->groupBy('month')->selectRaw('sum(total) as total, month')->get();
And this is my monthly query which doesn't work. I know that there is an issue with whereIn clauses in eloquent where they don't accept a big number of elements for some reason, but I'm wondering why one works and not the other one and if there is a solution to it. I also want it to be an object, I've tried using a raw query but it throws an array instead, and I would rather avoid using that. This is the one that worked.
$sortedMonthlySalesLastYear = DB::select( DB::raw("SELECT SUM(total) AS total, month FROM invoices WHERE year = '$lastYear' AND client_id IN ($client_ids_query) GROUP BY month"))
Schema::create('invoices', function (Blueprint $table) {
$table->id();
$table->string('month');
$table->integer('year');
$table->integer('week');
$table->integer('client_id')->index()->unsigned();
$table->integer('product_id')->index()->unsigned();
$table->integer('quantity');
$table->float('total');
$table->double('discount');
});
This is what my invoices migration looks like, the client relates to the user and that's how I get the arrays.
This is what the monthly query returns:
[2022-05-02 23:40:05] local.INFO: monthly sales:
[2022-05-02 23:40:05] local.INFO: []
And this is what the weekly one returns (it's a larger set
but this is a sample of what it throws to show its working.)
[2022-05-02 23:42:42] local.INFO: weekly sales:
[2022-05-02 23:42:42] local.INFO:
[{"total":536190.4699999997,"week":1},
{"total":568192.6700000003,"week":2},
{"total":1613808.48,"week":3},
{"total":878447.3600000001,"week":4}...]
An example of a few invoices I'm trying to process is this (there are more than 130K invoices in the database):
I'd appreciate any help and if you have a solution to this, I mostly just prefer to stay using eloquent for the code to look cleaner. Thank you.
I also have to add that the query returns the expected values if I sign in with any other user since the range of clients they have is much smaller.
I figured it out after so long. The only thing I did was implode the client_ids collection and then explode it into an array. No idea why it does accept a big array and not a big collection, and still no idea about the discrepancy between the queries.
$clients = Client::where('user_id', $user_id)->get('id');
$imp = $clients->implode('id', ', ');
$client_ids = explode(', ', $imp);
All queries work with that.
I have a gebruikers (meaning users) table. Gebruikers are grouped in a team (many to many relationship). Gebruikers can have a breakfast, diner and supper. They eat together with their team colleagues.
Meals are registered in a mealregistration table. So there is also a many to many relationship between the gebruikers table and the mealregistration table. A gebruiker can have many mealregistrations, a mealregistration has many gebruikers.
Not every team member takes every meal. Some gebruikers only have breakfast, or dinner, or supper, or any combination of meals.
This is my code for saving a mealregistration
$userid = Auth::user()->id;
$nieuwemaaltijd = ModelsMaaltijdregistratie::create([
'user_id' => $userid,
'datum' => $this->datum,
'afdeling_id' => $this->selectedAfdeling,
'type' => $this->type,
'prijs' => appsetting($this->datum,$this->type)
]);
$nieuwemaaltijd->gebruikers()->sync($this->selectedGebruikers);
the user_id is the id of the teamleader making the registration, afdeling_id stands for the team, type is breakfast, diner or supper and price is the money charged for the meal (I made a function in a helper class for that).
I'm asked to provide a list of users that take more than one meal a day and how many days (in a certain period) they take more than one meal.
So for example if gebruiker x takes breakfast and diner on Monday, only supper on Thursday and all three meals on Wednesday, he should be in the list with count 2 (since he took more than one meal on 2 days).
I'm getting close with:
$gebruikers = Gebruiker::whereHas('maaltijdregistraties', function ($query) {
$query->groupBy('datum')->havingRaw('COUNT(*) > 1');
})->get();
It gives me a list with all the gebruikers that have at least one day on which the took more than one meal.
But how can I display the number of days that they took more than one meal?
Thanks!
You may take a look at counting related models on the Laravel documentation.
$gebruikers = Gebruiker::withCount(['maaltijdregistraties' => function (Builder $query) {
$query->groupBy('datum')->havingRaw('COUNT(*) > 1');
}])->get();
echo $gebruikers[0]->maaltijdregistraties_count;
I have a Laravel 4.2 project where I get data from a SQL DB and I can display onto the page. I can select the single record just fine, but I want to also show the records around the one selected.
For example, I want to show the 5 records above and below the one selected. Im not sure how to do this in Laravel.
$gradschoolrange = MOGRadschool::where('Title', '=', $gradschool)->get();
In the above example $gradschool might be "Test College", it will return that with a value, but I want to show all the other related records around it with those values too. The results should look something like this:
ABC College
Another College
Blah College
Go To College
Test College
Yet Another College
Yo Yo College
College College
Something College
Eating College
As there's no ordering specified in your initial query, I'm assuming you want 5 next/previous records according to primary key (id? - if not, you would obviously need to change that) in the table?
Given that IDs may not be numerically sequential, we can't simply assume that the previous 5 rows will be the ID of the row with title = $gradschool minus 5, so wondered if this might work:
$initial = MOGRadschool::where('Title', $gradschool)->first(); // get the initial row with the title of $gradschool
$result = MOGRadschool::where('id', '<', $initial->id)->take(5)->orderBy('id', 'DESC') // new query getting the previous 5 rows, by ID
->union(MOGRadschool::where('id', '>', $initial->id)->take(5)) // union a second query getting the next 5 rows by ID
->get() // get the result as a collection
->add($initial) // add the initial row to the collection
->sort(); // sort the collection (by id) so that the initial row is in the middle
So the output is a collection containing the initial row in the middle, with up to 5 records either side. You also have the initial row to highlight the output, if you need that.
If you want it based on the IDs, which is what I understand from your issue, something like this should work:
$selectedGradSchool = MOGRadschool::where('Title', '=', $gradschool)->get()->first();
$aboveSelected = MOGRadschool::where('id', '<=', $selectedGradSchool->id)
->orderBy('id', 'desc')
->take('5')
->get();
$belowSelected = MOGRadschool::where('id', '>' $selectedgradSchool->id)
->take('5')
->get();
//Concatenate both results
$schoolRange = $aboveSelected->concat($belowSelected);
Now the collection should look similar to your desired result.
How to get the number of hours referring only to the one month between 2 dates?
For example, how to get count of hours for December for first or for second row at the screenshot?
I tried this (subMonths generated in the loop, so no worry about it):
$bookings = Booking::whereDate('departure_date', '>=', Carbon::now()->subMonths($i)->startOfMonth())
->orWhereDate('arrival_date', '<=', Carbon::now()->subMonths($i)->endOfMonth())->get();
and then:
foreach ($bookings as $book) {
echo Carbon::parse($book->departure_date.$book->departure_time)->diffInHours(Carbon::parse($book->arrival_date.$book->arrival_time));
}
But in this case I get count of hours for whole booking, how to get it only for December?
p.s. I need this for calculating the statistics (booking percentage).
You would likely need to ->addMonth() then go to the ->startOfMonth() then use diffInHours().
Carbon::parse($book->departure_date)
->addMonth()
->startOfMonth()
->diffInHours(Carbon::parse($book->arrival_date.$book->arrival_time));
I've omitted $book->departure_time otherwise the timestamp wouldn't be the first second of the first day of the month.
Let's say I have a table users with thousands of records, each with their name.
My goal is to draw a pie chart showing the most common names. I want to take, for example, the 9 most common names, and put the rest into a 'others' group.
I can't figure out how to use groupBy() and take(), or whatever, to achieve this.
Any ideas?
You can try using groupBy and count raw
$groups = DB::table('users')
->select(DB::raw('count(*) as user_count, name'))
->groupBy('name')
->orderBy('user_count', 'desc') //lorder desc or asc
->limit(5) //number of groups
->get();
dd($groups); you will see the user_count and name
Data for your pie chart would be user_count/total_user