I want to get data get based on orderBy('fee', DESC) from pivot table in laravel.
The condition is
Doctor::with('doctor_hospital_settings')
->when(request('sort-by') == 'highest-fee', function ($query) {
$query->whereHas('doctor_hospital_settings', function (Builder $query1){
$query1->orderBy('doctor_hospital_settings.fee', 'DESC');
})
})
->orderBy('id', 'ASC')
this(whereHas) runs the sub-query which does not sort the data according to Fee DESC.
It only sort data based on doctor id mentioned at the end.
orderBy('id', 'ASC').
The orderby is done in the subquery but i need this sort in main query not in subquery
Doctor Model
public function doctor_hospital_settings()
{
return $this->belongsToMany(Hospital::class, 'doctor_hospitals')->withPivot('fee');
}
How I can achieve this
You can't sort by a relationship using the query builder directly. This is because Laravel performs two queries. One to fetch the doctor_hospital_settings and one to fetch the fees. The fees itself are sorted, but after that they are connected to the doctor_hospital_settings which doesn't result in the same order anymore.
You have two options to make this work. The first one is using a join the second one is sorting the data based on the results you get back using the collection methods. It depends on the amount of data you get back. If you only get a view records back, the collections approach is the simplest. If you have a lot of data, the join is a better approach
Joins: https://laravel.com/docs/8.x/queries#joins
Collections: https://laravel.com/docs/8.x/collections
Related
I'm working on a custom pagination on a laravel query. I am not using laravel own paginate() because it doesn't suit my situation.
Basically something like this:
$items = MyModel::where('field', 'stuff')
->where('some other complex subquery')
->limit($limit)
->offset($offset)
->get();
The query works perfectly, but I also need to return the total number of items available to better display the pagination on the client.
One option i have is to clone the query and perform a separated count query, something like this:
$query = MyModel::where('field', 'stuff')
->where('some other complex subquery');
$totalCount = (clone $query)->count();
$items = $query->limit($limit)
->offset($offset)
->get();
the problem is, I have to perform two queries. I have several conditions on nested relationships and the query is not really lightweight, so I don't like the idea of doubling it.
Considering laravel itself need to do it inside its own paginate() method, are there some more efficient ways to perform this?
I have a use case in druid where real-time data comes in the format like,
task{
taskno;
category;
}
Here category can be "assigned" or "unassigned".Suppose tasks with the following came,
taskno:1,category:"assigned"
taskno:2,category:"unassigned"
taskno:3,category:"assigned"
taskno:4,category:"assigned"
Here if I perform a query with filter as "category" with count(*) on it ,I will get result as;
assigned:3
unassigned:1
Now a new event comes with
taskno:2,category:"assigned"
I want in such a way that the query results
assigned:4
unassigned:0
Is there any way I can do like this using Javascript UDF or something in druid?
Thanks.
You can first filter your query on task and than filter it on category with order as desc and limit 1. It should give you the desired result.
And in your function where you getting the results you can addup the counts, or you can write a post aggregation function to do the same in druid.
i'm trying to do something perhaps a bit too crazy with Eloquent right now, i have a database where i have the following Tables
Crons - (Has Many) - Campaign - (Has Many) - Leads - (Has Many) - Conversions
I need to get all leads from a Cron, that have no entries in the Conversions table in the last X amount of days
I'm thinking of using a Scope on the Cron model but i'm completely stuck on how to proceed from here.
public function scopeWithValidLeads($query) {
return $query->with(['leads' => function($q) {
}]);
}
So i need to get LEADS where the following is true.
A - The leads belong to a campaign associated with the Cron via a Many-To-Many relationship.
B - They have no record in the conversions table Under this specific campaign or if they do, that the lead is older than X amount of days.
You can get your desired result using doesntHave() method like this:
$x = 10; // last 10 days
$crons = Cron::doesntHave('compaign.leads.conversions')
->whereBetween('created_at', [Carbon::now(), Carbon::now()->addDays($x)])
->get();
Querying Relationship Absence: When accessing the records for a model, you may wish to limit your results based on the absence of a relationship. For example, imagine you want to retrieve all blog posts that don't have any comments. To do so, you may pass the name of the relationship to the doesntHave method
UPDATE
As per the updated question conditions, according to my understanding the leads can be obtained by:
$leads = Lead::whereHas('compaign', function($q) use($compaign) {
$q->has('crons')
->where('id', $compaign->id);
// Use the above line if in case of a compaign is to be filtered out
})->doesntHave('conversions')
->whereBetween('created_at', [Carbon::now(), Carbon::now()->addDays($x)])
->get();
Hope this helps!
Is there a way to get all joined table from a query?
For example:
query = Account::find()->joinWith(['gallery'])->joinWith(['articles'])->etc...
Is there any integrated method in yii2 that will return the above joined tables (or an event on which I could hook to get them manually)?
Solution suggested by #Beowulfenator shows only joins with relations (which added with joinWith() method.
To show all joins you need prepare the query like this:
$query = Account::find()
->join('...', '...')
->joinWith(['gallery', 'articles']); // By the way, you can reduce you code like this
$query->prepare();
This will transform yii\db\ActiveQuery to simple yii\db\Query which doesn't have joinWith property but has join property that shows exactly all joins.
You can var_dump and see it:
var_dump($query->join);
exit();
First element stores type of join, second - table name (note that it can be either string or array depending on used relation), third - on condition.
ActiveQuery class has joinWith public property. It's an array that contains information on all joins. It, among other things, contains joined table names.
More info here.
I have a design problem with SQL request:
I need to return data looking like:
listChannels:
-idChannel
name
listItems:
-data
-data
-idChannel
name
listItems:
-data
-data
The solution I have now is to send a first request:
*"SELECT * FROM Channel WHERE idUser = ..."*
and then in the loop fetching the result, I send for each raw another request to feel the nested list:
"SELECT data FROM Item WHERE idChannel = ..."
It's going to kill the app and obviously not the way to go.
I know how to use the join keyword, but it's not exactly what I want as it would return a row for each data of each listChannels with all the information of the channels.
How to solve this common problem in a clean and efficient way ?
The "SQL" way of doing this produces of table with columns idchannel, channelname, and the columns for item.
select c.idchannel, c.channelname, i.data
from channel c join
item i
on c.idchannel = i.idchannel
order by c.idchannel, i.item;
Remember that a SQL query returns a result set in the form of a table. That means that all the rows have the same columns. If you want a list of columns, then you can do an aggregation and put the items in a list:
select c.idchannel, c.channelname, group_concat(i.data) as items
from channel c join
item i
on c.idchannel = i.idchannel
group by c.idchannel, c.channelname;
The above uses MySQL syntax, but most databases support similar functionality.
SQL is made for accessing two-dimensional data tables. (There are more possibilities, but they are very complex and maybe not standardized)
So the best way to solve your problem is to use multiple requests. Please also consider using transactions, if possible.