Display best selling items by status - php

Explaining my problem, I have two tables in my database called order and order_details.
On my dashboard, I display the three best-selling items (currently work!). However, I would like to display only the best selling items THAT have the status = delivered.
Today, it works like this:
$top_sell_items = OrderDetails::with(['product'])
->select('product_id', DB::raw('SUM(quantity) as count'))
->groupBy('product_id')
->orderBy("count", 'desc')
->take(3)
->get();
The problem is that the order status is stored in another table, called orders, column order_status.
How can I create this rule and include it in my $top_sell_items?

if you relationship is done between this table already, you can use this code, if not you have to go to the OrderDetails Model and add new method orders
$top_sell_items = OrderDetails::with(['product', 'orders'])
->whereHas('orders', function($query) {
$query->where('status', 'delivered');
})
->select('product_id', DB::raw('SUM(quantity) as count'))
->groupBy('product_id')
->orderBy('count', 'desc')
->take(3)
->get();

You could either define a relationship between Orders and OrderDetails or use a join like so...
<?php
$top_sell_items = OrderDetails::with(['product'])
->join('orders', 'orders.id', '=', 'order_details.order_id')
->select('product_id', DB::raw('SUM(quantity) as count'))
->where('orders.order_status', 'delivered');
->groupBy('product_id')
->orderBy("count", 'desc')
->take(3)
->get();
More info here: https://laravel.com/docs/8.x/queries#joins

Depending if you desire this, the following solution might be the most efficient:
$products = Product
::whereHas('orderDetails.order', function ($query) {
$query->where('orders.order_status', 'delivered');
})
->withSum('orderDetails', 'quantity')
->orderBy('order_details_sum_quantity', 'desc')
->take(3)
->get();
It will directly return instances of Product. In addition it puts everything in a single query instead of the two that with produces.

Related

Get last record on GROUP BY using Laravel & MySql

I have two table (users and messages) .. I wrote a query to get all messages that users sent to me or I sent, using JOIN .. to get all the users I have contacted or they did.
as in the code below:
$users = Message::join('users', function ($join) {
$join->on('messages.sender_id', '=', 'users.id')
->orOn('messages.receiver_id', '=', 'users.id');
})
->where(function ($q) {
$q->where('messages.sender_id', Auth::user()->id)
->orWhere('messages.receiver_id', Auth::user()->id);
})
->orderBy('messages.created', 'desc')
->groupBy('users.id')
->paginate();
The problem here is when records grouped, I'm getting the old message not the new one according to its created_at .. So, I want to get the last record of the grouped records.
It seems like it would make more sense to make use of Eloquent's relationships here so that you can eager load the relationships instead of having to use join and group by:
$messages = Message::with('sender', 'receiver')
->where(function ($query) {
$query->where('sender_id', auth()->id())
->orWhere('receiver_id', auth()->id())
})
->orderByDesc('created') // is this meant to be 'created_at'?
->paginate();

I want to use multiple table use in Advanced Join Clauses

I need some help on my query. I use multiple tables with advanced join clauses but it shows invalid count and both has same value:
$parents = DB::table('users')
->select('users.id','users.full_name', 'users.email', 'users.avatar', 'users.signup_date', (DB::raw('count(children.id) as children_no')), (DB::raw('count(invitations.id) as invitations_no')))
->leftJoin('children', function ($join) {
$join->on('users.id', '=', 'children.userid')
->where('children.is_deleted', '=', 0);
})
->leftJoin('invitations', function ($join) {
$join->on('users.id', '=', 'invitations.user_id')
->where('invitations.is_deleted', '=', 0);
})
->where('users.is_admin', '=', 0)
->groupBy('users.id')
->get();
I think you can solve this problem with basic relationships in Laravel + soft deletes on the invitations and children table.
This will make your query less complex and you have the Laravel benefits.
<?php
$users = User::where('is_admin', false)
->has(['invitations', 'children'])
->withCount(['invitations', 'children'])
->get();
This wil select all none admins, with invitations and children.
Make sure you have soft deletes setup on children and invitations.
The withCount will add a count for the related relations.

How to order my query by most duplicates in Laravel?

On my website, users can post images.
Images can have tags.
There's 4 tables for this, the images table, the images_tag pivot table, the tag table, and of course the users table.
A user can have multiple images with the same tag(s).
I can pull up the tags a user has used across all his images with this query:
$userTags = Tag::whereHas('images', function($q) use($user) {
$q->where('created_by', $user->id);
})->get();
However, I want to make it so that I can order these tags based on how frequently a user uses them. In other words, I want to order by duplicates. Is this possible?
To achieve this, you're going to need to join the images_tags and images tables, count the number of tags, and order by those tags.
$tags = Tag::selectRaw('tags.*, COUNT(images.id) AS total')
->join('images_tags', 'tags.id', '=', 'images_tags.tag_id')
->join('images', 'images.id', '=', 'images_tags.image_id')
->where('images.created_by', $user->id)
->groupBy('tags.id')
->orderBy('total', 'desc')
->get();
The above query will only work in MySQL if the only_full_group_by option is disabled. Otherwise, you're going to need to either rewrite this to use a sub query, or do the ordering in the returned Laravel Collection. For example:
$tags = Tag::selectRaw('tags.*, COUNT(images.id) AS total')
->join('images_tags', 'tags.id', '=', 'images_tags.tag_id')
->join('images', 'images.id', '=', 'images_tags.image_id')
->where('images.created_by', $user->id)
->groupBy('tags.id')
->get();
$tags = $tags->sortByDesc(function ($tag) {
return $tag->total;
});
If you want to add this to your user model, per your comment, create a function similar to the following:
public function getMostUsedTags($limit = 3)
{
return Tag::selectRaw('tags.*, COUNT(images.id) AS total')
->join('images_tags', 'tags.id', '=', 'images_tags.tag_id')
->join('images', 'images.id', '=', 'images_tags.image_id')
->where('images.created_by', $this->id)
->groupBy('tags.id')
->orderBy('total', 'desc')
->limit($limit)
->get();
}

Laravel query doesn't want to select last one

I tried distinct before but somehow my query won't select the last comment. He always select the oldest comment. Then i tried it with groupBy instead of distinct. But this won't work either.
My current query:
\App\Comment::limit(5)->groupBy('comments.id')
->orderBy('comments.id', 'desc')
->join('topics', 'comments.topic_id', '=', 'comments.id')
->select('comments.user_id', 'topics.id', 'topics.name')
->whereIn('topics.cat_id', $cats)
->where([['comments.removed', '=', false],['topics.removed', '=', false]])
->get();
It's pretty long.
Hopfully someone can explain me why this won't work.
Errors found so far
groupBy is not needed
Your join statement join('topics', 'comments.topic_id', '=', 'comments.id') should be joining columns in table comments and topics
Fix
\App\Comment::select('comments.user_id', 'topics.id', 'topics.name')
->join('topics', 'comments.topic_id', 'topics.id')
->whereIn('topics.cat_id', $cats)
->where('comments.removed', false)
->where('topics.removed', false)
->latest('comments.id')
->limit(5)
->get();
PS: latest('comments.id') is handy for orderBy('comments.id', 'desc')
UPDATE
To get the latest comment for at most 5 recently updated topics, try this
\App\Comment::select('comments.user_id', 'topics.id', 'topics.name')
->from(DB::raw("(select * from comments where removed = 0 order by id desc) as comments"))
->join('topics', 'comments.topic_id', 'topics.id')
->whereIn('topics.cat_id', $cats)
->where('topics.removed', false)
->groupBy('topics.id')
->limit(5)
->get();
Try to use whereHas. You should do something like this:
\App\Comment::where('removed', false)
->whereHas('topic', function($q) use ($cats) {
$q->where('removed', false)
->whereIn('cat_id', $cats);
})
->limit(5)
->orderBy('id', 'desc')->get();
To achieve this, you must have the relations established by functions, such as topics (ie: hasMany) in Comment model.

Laravel Eloquent query get users from another model

I have another table called tableb and it has a user relationship defined through the user_id field.
I want to run a query against tableb where a certain date is within a certain range but then I want to grab the user table associated with that row but I only want it to grab the user if it's not been grabbed yet. I'm trying to do this all in 1 DB query. I have most of it done, but I'm having trouble with the unique part of it.
Here's what I have right now:
$tableB = TableB::select('users.*')
->join('users', 'tableb.user_id', '=', 'users.id')
->where('tableb.start_date', '>', date('Y-m-d'))
->get();
So right now I have 3 entries in tableB from the same user, and ideally I'd like to only get 1 entry for that user.
How would I go about doing this?
Since you're selecting only users data, just add a groupBy clause in your query.
$tableB = TableB::select('users.*')
->join('users', 'tableb.user_id', '=', 'users.id')
->where('tableb.start_date', '>', date('Y-m-d'))
->groupBy('users.id')
->get();
You should just add groupBy like this :
$tableB = TableB::select('users.*')
->join('users', 'tableb.user_id', '=', 'users.id')
->where('tableb.start_date', '>', date('Y-m-d'))
->groupBy('users.id')
->get
Try This Code
App/user.php
public function getrelation(){
return $this->hasMany('App\tableB', 'user_id');
}
In Your Controller
Controller.php
use App/user;
public funtion filterByDate(user $user)
{
$date = '2016-02-01';
$result = $user->WhereHas('getrelation', function ($query) use($date) {
$query->whereDate('tableb.start_date', '>', $date)
->first();
});
}

Categories