laravel table structure showing the most liked articles and less views - php

users can add articles and other users can like or dislike I need most liked with the less view
example :
article (A) has 500 views and 10 like - article (B) has 50 views and 10 likes
the order will be (B) than (A)
This is my database structure and I join them together:
articles table:
id | user_id | title | description | views | created_at | updated_at
likes table:
id | user_id | article_id | like_type | created_at | updated_at
query to get likes count :
Article::leftJoin('likes', 'likes.article_id', '=', 'articles.id')
->select('articles.*', DB::Raw('SUM( 2 * likes.like_type -1) as likes_count'))
->groupBy('articles.
->get();
how can i order ?

You can order by multiple columns in laravel by chaining orderBy.
In your case for example you will want to first order by "likes_count" descending (=biggest first) and then by views ascending (= smallest first, this is the default value).
So you will do:
return Article::select('title', DB::Raw('SUM(2*likes.like_type-1) as likes_count'))
->leftJoin('likes', 'likes.article_id', '=', 'articles.id')
->groupBy('articles.id')
->orderBy('likes_count', 'DESC')->orderBy('views')
->get();

Related

Multiple category id wise show product in laravel 9

I am trying to building ecoommerce system using laravel 9. Everything goes fine but Suddenly I got one issue. I want to show product based on category id but my product table category id store multiple. Bellow I am showing my table structure:
Product Table:
|---ID---|---Name---|---Cat_id---|---Status--|
| 1 | T-shirts | 1,2, | active |
| 2 | Pants | 4,3, | active |
| 3 | Sweaters | 5,2, | active |
Category Table
|---ID---|---Name---|
| 1 | General |
| 2 | News |
| 3 | Festival |
| 4 | Category |
Controller
public function category($slug)
{
//
$cat = Category::where('slug', $slug)->first();
$products = Product::whereIn('cat_id', [$cat->id])->where('status', 'active')->orderby('id', 'asc')->paginate('12');
return view('frontend/Catproducts', compact('products', 'cat'));
}
Now I want when I am click on "NEWS" category I want to see two product. How can I fix it
As #aynber said in the comments, best solution is to normalize the database, so you have a setup like this:
Categories table:
id
name
Products table:
id
name
status
Product_categories table:
id
product_id
category_id
With a belongsToMany relationship from Product to Category(and back), your query should look something like:
$categoryIdArray = [2];
Product
::whereHas('category', function($query) use($categoryIdArray) {
$query->whereIn('id', $categoryIdArray);
})
->get();
It is still possible with your current setup though, while a little hacky:
$cat = Category
::where('slug', $slug)
->first();
$catId = $cat->id;
$products = Product
::where(function($where) {
$where->where('cat_id', 'like', "$catId,%")//Look for first cat in col, don't forget trailing comma
->orWhere('cat_id', 'like', "%,$catId,%")//Look for appended cat between commas
})
->where('status', 'active')
->orderby('id', 'asc')
->paginate('12');
This will work on small scale, but because we are using like, mysql needs to check ALL records, and cannot optimize the query. That's the reason why normalization is important :)

Eloquent sub-query for if the row is the latest one

I have the following subquery:
->whereHas('statuses', function($query){
$query->where('status_id', request('status'));
})->orderBy(...)->paginate();
For simplicity's sake I have hidden the full query. Let's say I have the pivot table user_status. User has many statuses and a status can also have many users (unusual, I know. Just consider it as an example). So when I query the pivot table user_status as described above, I get those rows that have the requested status id. But I also want to add the constraint that the row must be the latest one for that particular user (not in entire table). Here is how the user_status table looks like:
+---------+-----------+---------------------+
| user_id | status_id | created_at |
+---------+-----------+---------------------+
| 1 | 1 | 2018-09-03 18:39:14 |
| 1 | 8 | 2018-09-03 18:51:42 |
+---------+-----------+---------------------+
In this scenario, if the requested status is 1, I don't want this row to be returned, because status_id 1 is not the latest one for the user_id 1 (see the time difference in create_at column).
How can I achieve that?
You can achieve that by using another condition with a nested query.
->whereHas('statuses', function($query){
$query->where('status_id', request('status'))
->whereIn('user_status.id', function($query) {
$query->selectRaw('MAX(id)')
->from('user_status')
->groupBy('user_id');
});
})->orderBy(...)->paginate();
The nested query will select only latest rows(assuming user_status.id is auto-increment)
I define a relation in user model as :-
public function latest_statuses() {
return $this->hasMany(Status::class,'user_id','id')->orderBy('created_at','DESC')->take(1);
}
And after that written query as :-
$status = \App\User::with('latest_statuses')->whereHas('latest_statuses', function($query){
return $query->where('status_id', 1);
})->get();
It works for me.

Join 2 tables together and get return all data where it matches (PHP/Laravel5.2 using MySQL)

I have a variable called $category which a user selects. On submit I need to look inside a table (profiles) for where the $category matches and pull back all of those profiles then look into the likes table and return all matching records for the returned profiles.
My database looks like:
TABLE: profiles
ID | username | category
-------------------------
1 | x | band
2 | y | airline
3 | z | airline
TABLE: likes
ID | account_id | likes | created_at
---------------------------------------
1 | 2 | 1000 | 21/03/2016
2 | 2 | 2000 | 22/03/2016
3 | 1 | 3000 | 22/03/2016
My code is the following:
$category = "band";
$profiles = DB::table('profiles')
->join('likes', 'profiles.id', '=', 'likes.account_id')
->where('category', '=', $category)
->select('profiles.*', 'likes.likes', 'likes.created_at')
->get();
account_id in the likes table will be the same as id in the profiles table. Also there maybe multiple like records for each profile.
The query just doesn't seem to work and it returns nothing back. I'm using laravel 5.2.
$profiles = DB::table('profiles')
->leftJoin('likes', 'profiles.id', '=', 'likes.account_id')
->where('profiles.category', '=', $category)
->select('profiles.*', 'likes.likes', 'likes.created_at')
->get();

Laravel 2 table join with all from left table merged with members of the right table with a given FK value

I have two tables in Laravel of which I am seeking to merge them together, however, I want to return every single value of the first table (without duplicates) along with only values from the second table that have a FK value of 2. If there is no entry with a FK of 2, it joins with a value of null.
To make my question a little more clear, lets say we have the following tables:
TV Shows Table
ID | Show
1 | First Show
2 | Second Show
3 | Third Show
Favorites Table
Show_ID | Member_ID
1 | 1
3 | 1
1 | 2
2 | 2
I am looking to merge them into a resultant set like the following when I join the tables with a member ID of 2(disregarding the joined 'Show_ID' column):
Merged Table
ID | Show | Member_ID
1 | First Show | 2
2 | Second Show | 2
3 | Third Show | null
Thanks.
Not 100% I understood, so hope this is what you're looking for.
I've renamed some of the column names to make things a little clearer.
DB::table('shows')
->select(
'shows.id as show_id',
'shows.name as show_name',
'member.id as member_id'
)
->leftJoin('favourites', 'shows.id', '=', 'favourites.show_id')
->get();
Left join will allow there to be null in member_id if it isn't present on the join.
You can add this to restrict to member ID of two:
DB::table('shows')
->select(
'shows.id as show_id',
'shows.name as show_name',
'member.id as member_id'
)
->leftJoin('favourites', 'shows.id', '=', 'favourites.show_id')
->where('member.id', 2)
->get();
I solved it myself. I needed to do a functional join like so:
DB::table('shows')
->leftJoin('favorites', function($q) use $memberID)
{
$q->on('shows.ID', '=', 'favorites.show_ID')
->where('favorites.member_ID', '=', $memberID);
})->get();

Selecting data from 3 tables with limit

I have 3 tables ppc_offers, survery_offers,find_offers ( from admin section, i enter data into these tables)
Now on front end, i want to display latest 3 offers from these tables.
i.e. latest 3 will come, they can be from single table or multiple tables... it just has condition "latest 3"
How can i do this?
Laravel provides any way to do this?
or do i need to have any master table?
or can you suggest me regular SQL query for this?
Please help.
Thanks.
PPC Table:
-------------------------
id | integer
title | varchar
url | varchar
description | varchar
created_at | timestamp
updated_at | timestamp
--------------------------
survey Table:
-------------------------
id | integer
title | varchar
created_at | timestamp
updated_at | timestamp
--------------------------
find code Table:
-------------------------
id | integer
title | varchar
url | varchar
description | varchar
code | varchar
created_at | timestamp
updated_at | timestamp
--------------------------
Make 3 queries union them with the same names for columns
select * from
(
(query1 order by id desc limit 3) x
union
(query2 order by id desc limit 3) y
union
(query3 order by id desc limit 3) z
(
As a recommendation, it might make more sense to include all 3 of these offers in one table, and use an "offer_type" id to distinguish them from each other, instead of using 3 different tables. It might simplify your code.
I believe this may work with your current setup:
$ppc = DB::table('ppc_offers')
->select('title', 'url', 'description', 'NULL as code', 'updated_at');
$survey = DB::table('survey_offers')
->select('title', 'NULL as url', 'NULL as description', 'NULL as code', 'updated_at');
$find = DB::table('find_offers')
->select('title', 'url', 'description', 'code', 'updated_at');
return $ppc->unionAll($survey)->unionAll($find)
->orderBy('updated_at', 'desc')
->take(3)
->get();

Categories