Laravel OrderBy relationship count without loading models (count) - php

I have an episodes table and an episode_Listen table, which is a One episode to Many listens
I want to get the 6 episodes with highest listens. I've tried every single solution like the following:
$trending = Episode::where('active', true)
->get()->sortBy(function($podcast) {
return $podcast->latestListens;
});
Or
$trending = Episode::where('active', true)
->withCount('listens')
->orderBy('listens_count', 'desc')
->get();
Or
$trending = Episode::join('episode_listens', function ($join) {
$join->on('episode_listens.episode_id', '=', 'episodes.id');
})
->groupBy('episodes.id')
->orderBy('count', 'desc')
->select((['episodes.*', DB::raw('COUNT(episode_listens.podcast_id) as count')]))->paginate(6);
But the execution time always exceeds 6 seconds, because I've around 500k listens records in the database, and they'll go millions in a very short period of time.
Any thoughts?
Thanks in advance

Related

Laravel advanced query

Affiliate has many affiliatesHistory, affiliatesHistory belongs to affiliate, how to make the following query?
Take affiliates, where has affiliatesHistory, if affiliatesHistory records count is equal to 1, then do not take affiliatesHistory, which has status of uninstalled.
$affiliates = $user->affiliates()
->whereDoesntHave('affiliatesHistory', function ($q) {
$q->where('affiliates_histories.status', 'Installed earlier')
->orWhere('affiliates_histories.status', 'Uninstalled / Installed earlier');
The following query works, but I need to not take those affiliates, where affiliatesHistory count is equal to 1 and the status is uninstalled.
Any help will be appriaciated.
So, for what I understand you want to get the affiliates which affiliatesHistory status is Installed earlier. If this is the case then try this:
$user_affiliates = $user->affiliates();
$affiliates = $user_affiliates->whereHas('affiliatesHistory', function($q){
$q->where('status', 'Installed earlier');
})->get();
dd($affiliates);
For your case if there are more than one affiliatesHistory items then return else if there is only one affiliatesHistory then it should not contain Uninstalled status, I guess you can use conditional count to get desired results as
$affiliates = Affiliate::withCount([
'affiliatesHistory',
'affiliatesHistory as affiliatesHistoryUninstalled_count' => function ($query) {
$query->where('status', 'Uninstalled');
}
])->where('user_id', $user->id)
->havingRaw('affiliatesHistory_count > 1 OR (affiliatesHistory_count = 1 AND affiliatesHistoryUninstalled_count = 0)')
->get();

Filter elements by counting their relationship Laravel5

I have two tables, the typical master-detail, what I intend to do is obtain the master's records, while the registration number obtained by means of a where of the relationship is greater than n
I've been doing this until now
Master::withTrashed()
->with('details')
->withCount(['details' => function ($query) {
$query->whereDate('date_init', '<', Carbon::now()->toDateString());
}]);
with this I get the master and its details with the given conditions, but there are teachers that the count of the relationship is 0, that I want to ignore. How can I do this?
What you are looking for is the following query:
Master::withTrashed()
->with(['details' => function ($query) {
$query->whereDate('date_init', '<', now());
}])
->whereHas('details', function ($query) {
$query->whereDate('date_init', '<', now());
})
->get();
The query literally means:
Give me all Masters, also the deleted ones, which have at least one attached Detail with an initialization date in the past. Also eager load all attached Details which have been initialized in the past.
Master::withTrashed()
->has('details')
->with('details')
->withCount(['details' => function ($query) {
$query->whereDate('date_init', '<', Carbon::now()->toDateString());
}]);
Fixed whereHas to has, as pointed out by Namoshek.

Get value with max amount in Laravel

I'm using laravel-page-view-counter to count visits of my products and it's working just fine, what i need to do is to get list of top 10 products by their visits (get 10 products which has largest number of visits).
Here is what I have:
$visits = Product::join('page-visits', function ($join) {
$join->on('products.id', '=', 'page-visits.visitable_id');
})->get();
$sorted = $visits->sortBy(function ($product, $key) {
return count($product['visits']);
});
But It return from lowest product visits to highest one (it shows product with 0 visit till product with 100 visits) I need reverse method of that to show (product with 100 visits first).
You can do it easily with query builder and some raw queries like this:
$visits = DB::table('products')
->join('page-visits','products.id','=','page-visits.visitable_id')
->select(DB::raw('count(visitable_id) as count'),'products.*')
->groupBy('id')
->orderBy('count','desc')
->take(10)
->get();
I hope you will understand.

Laravel `Item` has many, return only if ALL are in the past

In my project, a hire can have many hire_days. Each hire_day is has a start and end timestamp.
I want to create a query where it will return only the hires where ALL of it's associated hire_day.end times are in the past.
So far, my query:
$hires = Hires::join('hires_days', function ($join) {
$join->on('hire_id', '=', 'hires.id');
})
->select('hires.id', 'hires.account_id', 'hires.job_number', 'hires.site_id', \DB::raw('MAX(end) AS end'))
->orderBy('hires_days.end', 'asc')
->groupBy('hires.id')
->paginate(10);
This will return hires if at least one of their hire_days is in the past, ignoring the fact that there are some associated hire_days still in the future.
I think that what you need is to add to your query:
->having('end', '<', time())

Laravel groupBy

I'm trying to redesign my Laravel 4.2 code and like to group a list from results over the last days.
code:
public function getTrending($type = null, $category = null)
{
$posts = $this->posts($type, $category)->with('comments', 'votes', 'category', 'user', 'votes.user')
->leftJoin('votes', 'posts.id', '=', 'votes.post_id')
->leftJoin('comments', 'posts.id', '=', 'comments.post_id')
->select('posts.*', DB::raw('count(comments.post_id)*7 + count(votes.post_id)*30 + posts.views as popular'))
->groupBy('posts.id')->with('user')->orderBy('popular', 'desc')->whereMonth('posts.created_at', '>=', date('n', strtotime('-1 month')))
->paginate(perPage());
return $posts;
}
I want to group the results as it is (relevance: comments, votes, visit) + grouping the results on a daily base.
Like:
Today (with Date xx.xx.xx)
result 1 (Max Votes, Comment, ...)
result 2
result 3
Yesterday (with Date xx.xx.xx)
result 4 (Max Votes, Comments, ...)
result 5
result 6
Is this possible?
You can use Carbon;
->groupBy(function($date) {
return Carbon::parse($date->created_at)->format('Y'); // grouping by years
//return Carbon::parse($date->created_at)->format('m'); // grouping by months
});
No I don't believe you can group your data in a single query like that.
Assuming your code is giving you the dataset you desire, without grouping by date, I would loop over the dates I want and get the data for every day and format it with the date heading etc.

Categories