Laravel pagination with distinct - php

I'm trying to use distinct with pagination but my pagination seems to ignore the total records of my distinct and it makes my pagination all messed up.
I have the following query:
$log_data_list = DB::table('logs')->leftjoin('users','logs.user_id', 'users.id')
->select(DB::raw("distinct on (logs.action,logs.action_table)logs.user_id,users.username as username,logs.created_at as tanggal,logs.ip_client as ip_client,logs.action as tindakan,logs.action_table as tabel,logs.no_laka as no_laka,logs.change_id as id"))
->paginate(5);
Can anyone help me with a solution? Thanks in advance

Instead of using a distinct in this fashion, why not have the log actions stored uniquely in a relational table using methods firstOrCreate / firstOrNew on storing the actual log.
You then would be able to use a proper eloquent model to paginate log actions table that would already be a unique list and use the ID of selection action to get all related logs.
table.logs id,action_id,users_id,...
table.logs_actions id,action_name
This would be less costly than a select distinct especially on a huge table.

Related

Laravel collection count() takes too long

I have a contacts table and a contact_list table, a contact_list has many contacts, contacts table has a is_active field.
to get the number of active contacts for a contact_list i use the query builder as follows:
$contact_list->contacts()->where('is_active', 1)->count();
if the number of contacts is too big the query takes too long.
is there a better way to implement this?
as I can see you want to optimize the performance of your request.
to achieve that you should use eager-loading, so your new request should be like below:
$contactList = App\ContactList::with(['contacts' => function ($query) {
$query->where('is_active', 1);
}])->count();
For more information about how Laravel implement eager-loading please check the link of documentation: eager-loading documentation
With InnoDB COUNT() works slowly for tables with million rows.
That's a problem with count() as the InnoDB engine locks the table per row, and if the table is being changed on a regular bases the count() function is not trivial.
The Eloquent ORM doesn't differenciatie between InnoDB or MyISAM so the count() process always triggers something like SELECT COUNT(*) AS aggregate FROM table.
If you change the query with this one SELECT COUNT(1) FROM table you will realize that the count() process is way faster.
So in Laravel that would be reduced to something like:
Model::select(DB:raw('count(1)'))->first();
Or in your case
$contact_list->contacts()->select()->where('is_active', 1)->count();

Select rows with equal values

How to do in Laravel?
1) get from table rows where user_id has the equal values?
2) return sum of some_amount values from this selected rows
Table:
- id;
- user_id;
- some_amount;
Table has bunch of certificates with some amount of money that belongs to different users. I need to find all certificates that belongs to one user (one user can have few certificates) and count how much money he have from all his certificates
Given you aren't looking for a solution to query this for an individual user, it sounds like you want to group by the user and sum the result of certificates.
The answer from #PhilCross is pretty close, you'd just need to modify it to add the group clause and remove the where condition. Something like this:
ModelName::groupBy('user_id')->sum('some_amount');
or
\DB::table('table_name')->groupBy('user_id')->sum('some_amount');
Generally eloquent or the query builder will have a method that relates to how you would do this in raw SQL.
I find it helpful to write out or think about how I would write the raw SQL and then slowly fill the eloquent or query builder in from that.
If you use a Model:
ModelName::where('user_id', 1)->sum('some_amount')
If you're using the query builder:
\DB::table('table_name')->where('user_id', 1)->sum('some_amount');
This is the documentation for the query builder:
https://laravel.com/docs/5.6/queries
Models: https://laravel.com/docs/5.6/eloquent
Model Relationships: https://laravel.com/docs/5.6/eloquent-relationships
Collections: https://laravel.com/docs/5.6/collections

How to use GroupBy and OrderBy at the same time in Laravel 5.5

Am trying to query messages and group them by conversations and get the last message in each conversation, the structure of my table is
Table Messages(id(int), user_from(varchar), user_to(varchar), message(text), read(bool), chat_id(int), created_at(time_stamp), updated_at(time_stamp))
After searching for quite sometime here is what i think may solve my problem but i dont know how to implement this in Laravel 5.5 with eloquent or Query Builder
SELECT * FROM messages WHERE id IN(
SELECT MAX(id)
FROM messages
GROUP BY chat_id
)
I know it has been a while and you must have a solution for it. But I met a similar problem and just spent over 1 hour on it, so I think it worthy to confirm the solution here.
Yes, using Max could deal with the situation here. I used query builder, it could be like:
DB::table('messages')
->selectRaw('max(id) as id, chat_id') // you may add other fields
->groupby('chat_id')
->orderby('id') // you may use other fields to sort
->get();

Can Laravel using join table to get data?

Just some random thought, can laravel using join table rather than using eloquent relationship. Because most of answers that i read in here suggest to using relationship like belongstoMany, belongsto and other eloquent relationship. If can, it should be nice if u guys giving me some sample code about how to do that. Sorry for the silly question. Thank you
A basic example using something I created a while ago using joins which were a forum thread table and a forum replies table. See below:
$forum = Forum::where('forumType', '=', $topic->forumType)
->leftJoin('forum_replies','forum_topics.forumid','=','forum_replies.topic_id')
->groupBy('forum_topics.forumid')
->orderBy('forum_replies.updated_at', 'DESC')
->get();
The above examples joins the forumid from forum_topics table to the forum_replies table's topic_id
Not a very tidy way of doing it though, you should definitely approach this by using relationships instead.
The code above was converted some time ago to relationships instead of using joins.
yes you can use the join as per your requirement if you don't want to add relationship like this
user::select('in_user_id', 'st_first_name', 'st_last_name',
'in_contact_no', 'email', 'tbl_city.st_city_name',
'tbl_usertype_master.st_usertype_name', 'tbl_center.st_center_name',
'is_active')->leftjoin('tbl_city', 'tbl_city.in_city_id',
'tbl_user.in_city_id')->
leftjoin('tbl_usertype_master','tbl_usertype_master.in_usertype_id',
'tbl_user.in_usertype_id')->leftjoin('tbl_center',
'tbl_center.in_center_id', 'tbl_user.in_center_id');
in this manner you can use join in laravel here i use for display user from User table
Hope this helps you
Thank You
The Laravel query builder supports almost all SQL sentences, you can see all available methods here https://laravel.com/docs/5.5/queries

Id Column Overwritten by Join

Using Laravel 4.2 & MySQL.
I have an applications table with an id and a fit_score_id column, and a fit_scores table with an id column. It's a basic "belongs to" relationship.
The following code:
$query = Application::join('fit_scores', 'applications.fit_score_id', '=', 'fit_scores.id');
$collection = $query->get();
...produces a collection of Application models with the id property set to the value of the fit_score_id. What am I doing to cause this?
I should note that it is necessary to do this join rather than simply using eloquent relations, because I'm going to want to order the results by a column on the fit_scores table. I don't believe this is possible using Eloquent without an explicit join.
The best way to solve this is by chaining the join method to a select method as following:
Application::select('*', \DB::raw("applications.id as appid"))
->join('fit_scores', 'applications.fit_score_id', '=', 'fit_scores.id')
->get();
Explained: The solution simply suggest that instead of thinking to prevent the behavior of overwriting the first id with the joined id, we can hook into the primary selection query (before joining) and change the label of the id column into something else (in this case 'appid'). By doing so, we end up with both the id of the parent table being labeled 'appid' and the id of the joined table being labeled 'id' again while they lives together on the final result.
I was able to find a possible solution using this answer:
Laravel 4 - JOIN - Same column name
Basically, since Laravel does not automatically prefix column names with table_name. for joined tables, we need to manually work around it by aliasing any conflicting column names in joins. Adding this select statement to my query did it:
->select(DB::raw("applications.*, fit_scores.*, applications.id as id"))
It depends on what you need but probably you can achieve it using eager loading. In case you need to mix joins and eager loading check this out. http://www.jmilan.net/posts/eager-loading-joins-in-laravel

Categories