I'm new on Laravel & Eloquent. I have Users, Products and Votes tables on my DB. Users can vote (0 to 5) on products, so it is a "many to many" relationship, with the Votes table acting like a pivot:
Users: id, name, email, password
Products: id, name, model, brand
Votes: user_id, product_id, vote
I mapped this schema like this:
// User model:
public function product_votes()
{
return $this->belongsToMany('App\Product', 'votes')->withPivot('vote');
}
// Product model:
public function product_votes()
{
return $this->belongsToMany('App\User', 'votes')->withPivot('vote');
}
So John can vote 5 on product X and 0 on product Y. Bob can vote 2 on product X, 3 on product Y, and so on...
I'm trying to query all products, with the sum of votes of each one of them. Something like:
SELECT p.*, (SUM(v.vote) / COUNT(*)) as votes FROM products p INNER JOIN votes v on v.product_id = p.id GROUP BY p.id
How can I do that with QueryBuilder? My mapping is right?
The following will do the trick:
Product::select('products.*', DB::raw('SUM(vote)/COUNT(*) as votes'))
->join('votes', 'votes.product_id', '=', 'products.id')
->groupBy('products.id')
->get();
You can see the query that will be run by calling toSql() instead of get().
Related
I have 3 tables:
Shifts {vehicled_id, user_id, subdriver_id)
Users {user_id, subdriver_id)
Vehicles {vehicle_id}
I want to group Shifts when I join with Users and Vehicles but some shifts only have user_id or subdriver_id and some have both.
This is the picture of shifts tables.
The result I want is a groupBy of vehicle_id and:
If it has only user_id or subdriver_id it will return {user_id, vehicle_id, shift_id (it can be an array)}
or {subdriver_id, vehicle_id, shift_id (it can be an array)}.
If it has both user and subdriver it will return {user_id, vehicle_id, shift_id(it can be array)}
shift_id is based on user_id and vehicle_id or subdriver_id and vehicle_id.
How can I groupBy and return a result like this?
You have to use CASE statement which goes through multiple conditions and return a value based on respective condition.
DB::table('shifts')
->select(DB::raw('CASE WHEN shifts.user_id IS NULL THEN shifts.subdriver_id WHEN shifts.subdriver_id IS NULL THEN shifts.user_id ELSE shifts.user_id END as user_id, shifts.vehicle_id, GROUP_CONCAT(shifts.id) as shift_id'))
->leftJoin('users as u1','u1.id','shifts.user_id')
->leftJoin('users as u2','u2.subdriver_id','shifts.subdriver_id')
->groupBy('shifts.vehicle_id')
->get();
I have 2 tables in my database.
books and ratings
in books
id, name
in ratings
id, book_id, rating
i have set has many relationship for these models.
So in Book model -
public function ratings()
{
return $this->hasMany('App\Rating');
}
in Rating Model -
public function book()
{
return $this->belongsTo('App\Book');
}
Now i want to fetch all books with there average rating but order by high rating.
so i high rated books first and then low ratings.
So How i can join 2 tables to achieve this result.
Thanks.
You can use a modified withCount():
$books = Book::withCount(['ratings as average_rating' => function($query) {
$query->select(DB::raw('coalesce(avg(rating),0)'));
}])->orderByDesc('average_rating')->get();
Books::withAvg('ratings', 'rating')->orderBy('ratings_avg_rating', 'desc')->take(5)->get();
this works in Laravel 8
Via Collections*
$books = Book::with('ratings')
->get()
->sortBy(function($bk, $key) {
if($bk->rating) {
return $bk->rating->rating;
}
return null;
});
Via Joins
$books = Book::join('rating', 'rating.book_id', '=', 'book.id')
->orderBy('ratings.rating', 'desc')
->select('books.*')
->get();
That query would look something like this:
SELECT book.id, AVG(ratings.rating) AS avg_rating
FROM ratings
JOIN book ON book.id = ratings.book_id
/* WHERE AVG(ratings.rating) > 4 You could say only return results where rating > 4 */
GROUP BY book.id
ORDER BY AVG(ratings.rating) DESC LIMIT 5;
You need to join the two tables, use an aggregate function with a group by on the book. Then just sort and limit the results.
UPDATE:
In response to your question:
SELECT book.id, COALESCE(AVG(ratings.rating), 0) AS avg_rating
FROM book
*LEFT* JOIN ratings ON book.id = ratings.book_id
GROUP BY book.id
ORDER BY AVG(ratings.rating);
Use of a view might be something of a compromise between ease of the ORM and sanity in your querying.
I have 3 tables, Order, Products, Order_Products. I need get all field from order and products, thats ok using hasManyThrough(). But i need 1 more field from Order_products. How can i get this field ?
public function products()
{
//in order model
return $this->hasManyThrough('App\Models\Product','App\Models\OrderProduct','order_id','id','id','product_id');
}
using sql i need query like
SELECT
products.*, order_products.order_id, order_products.count as order_count
FROM
products
INNER JOIN order_products ON order_products.product_id = products.id
WHERE
order_products.order_id = 2
You can access intermediate table fields by using pivot attribute on model.
Lets say you have product, Then you can access count field of orders_products
$product->pivot->count;
I have the following tables:
Dishes
id
name
Customers
id
name
Ingredients
id
name
Dishes_Ingredients (table to put in relation dishes and ingredients)
id
dish_id
ingredient_id
Customers_Allergic_Ingredients (customers are allergic to certain ingredients)
id
customer_id
ingredient_id
Customers_Intolerance_Ingredients (customers are intolerant to certain ingredients)
id
customer_id
ingredient_id
I need to get the following information from the database: for a given customer_id, I want to retrieve all the dishes which the customer is not allergic to and not intolerant to, using Laravel Query Builder.
This is what I tried so far:
$dishes = DB::table('dishes')
->join('dishes_ingredients', 'dishes.id', '=', 'dishes_ingredients.dish_id')
->join('customers_allergic_ingredients', 'dishes_ingredients.ingredient_id', '<>', 'customers_allergic_ingredients.ingredient_id')
->join('customers_intolerance_ingredients', 'dishes_ingredients.ingredient_id', '<>', 'customers_intolerance_ingredients.ingredient_id')
->where('customers.id', 1)
->select('dishes.id', 'dish_translations.name')
->get();
Try to use Laravel Eloquent: Relationships
this will save your time & your code will be more simply....
https://laravel.com/docs/5.2/eloquent-relationships
I don't know Laravel but if you just want to solve your problem:
SELECT *
FROM Dishes d
WHERE d.id NOT IN
(
SELECT DISTINCT dish_id
FROM Dishes_Ingridients
WHERE ingredient_id IN
(SELECT DISTINCT ingredient_id FROM Customers_Allergic_Ingredients cai WHERE cai.customer_id = ?)
OR
ingredient_id IN
(SELECT DISTINCT ingredient_id FROM Customers_Intolerance_Ingredients cii WHERE cii.customer_id = ?)
)
$dishes = DB::table("dishes AS a")
->select(array("a.*" ))
->join("dishes_ingredients AS b", "a.id", "b.dish_id")
->join("Customers_Allergic_Ingredients AS c", "b.id", "=", "c.ingredient_id")
->where("c.customer_id", "!=", $customer_id)
->groupBy("a.id")
->get();
This will give you all dishes made with ingredients that the customer is not allergic to
I'm creating a ranking of players badges and I'm stuck with db query.
Tables:
user(id), club(id), club_user(user_id, club_id), badges(user_id)
I would like to get list of all users from specified club (for example club.id = 1) with amount of badges they have. Results should be ordered by number of badges.
How to create that kind of db query? Is it possible with Eloquent?
Should it be made with db::table and join?
Table user
id|name
1|John
2|Robert
3|Kate
Table club
id|name
1|Sunshine Club
2|Example Club
Table club_user
user_id|club_id
1|1
2|1
3|2
Table bagdes
id|name|user_id|club_id
1|Champion|1|1
2|Some badge|1|1
3|example|2|1
4|Gold Badge|3|2
so if I would like to get ranking of users from club 1, ordered by badge count.
I should get:
name|number of badges
John|2 (badges)
Robert|1 (badge)
Kate is not it this club.
Try this
select user.name ,user.id as userid , (select count(bagdes.id) from
bagdes where user_id= userid)
as total_badges from user inner join club_user on
user.id = club_user.user_id where club_user.club_id = 1
You will get your output.
Finally I made it with this DB::table query:
$users = DB::table('users')
->select('users.name', DB::raw('count(*) as badges'))
->join('badges', 'badges.user_id', '=', 'users.id')
->where('badges.club_id', 1)
->groupby('users.id')
->orderBy('badges', 'DESC')
->get();