I would like to order my products by the those who do have the most likes. I have one products table, one likes table and one users table.
This is how my likes table looks like: id, user_id, product_id, value
The value
can either be 1
or -1
which is equal to one like or one dislike.
In my products model I have defined those relationships:
public function likes()
{
return $this->belongsToMany('App\Models\User', 'products_likes', 'product_id', 'user_id')->withPivot('value')->withTimestamps();
}
public function productLikes()
{
return $this->hasMany('App\Models\ProductLike');
}
However, now I would like to get the first 20 products which have the most sum
of likes. This is how I tried to solve this, however, I cannot solve my problem...
$products = Product::select('products.*', DB::raw('SUM(products_likes.value) as sumLikes'))
->join('products_likes', 'products_likes.product_id', '=', 'products.id')
->orderBy('sumLikes', 'DESC')
->get();
However, this results in a weird group by sql problem:
QLSTATE[42000]: Syntax error or access violation: 1140 Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause (SQL: select `products`.*, SUM(products_likes.value) as sumLikes from `products` inner join `products_likes` on `products_likes`.`product_id` = `products`.`id` order by `sumLikes` desc)
Does anyone knows how I can archive this? I want to have my database to perform the ordering job and not Laravel. I have found some solutions here as well but they suggest to perform an all()
and with("likes")
query and use sortByDesc
after the query got executed ( here ). But this brings down performance.
Kind regards
From laravel 5.2 onwards, you can use the withCount
method to add a 'likes_count' subquery column, which can be customized like this:
Product::query()
->withCount(['likes as sumLikes' => function ($query) {
return $query->select(\DB::raw('SUM(products_likes.value) AS sumLikes'));
}])
->orderBy('sumLikes', 'DESC')
;
A similar result can be achieved on Laravel 5.1 or older versions by writing the subquery yourself:
$subquery = ProductLike::query()
->selectRaw('SUM(product_likes.value) as sumLikes')
->whereRaw('product_likes.product_id = products.id')
;
Product::query()
->addSelect(DB::raw($subquery->toSql()))
->orderBy('sumLikes', 'DESC')
;
Another way would be using joins, like you were attempting to, but you need to GROUP BY the products for it to work.
Product::query()
->addSelect(DB::raw('SUM(products_likes.value) as sumLikes'))
->join('products_likes', 'products_likes.product_id', '=', 'products.id')
->groupBy('products.id')
->orderBy('sumLikes', 'DESC')
;
You may need to specify the columns in your select, and group by each one of them, depending on your Database Engine.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.