User roster, joining a table but loosing data - php

I need some help with a query (using Laravel framework). I'm building a user roster with a few columns that incude the users ratings. Basically, it selects all the active users who have initials and joins the user ratings table to select the ratings for the respective users. The where_in is to select only specific ratings. My issue is on the roster, it only selects one rating, rather than all of them (if the user has more than one rating). I've also tried without the group_by, but then the users are duplicated on the table depending on the number of ratings they have (example: if the user has 2 ratings, their row is displayed twice on the roster).
Query:
$users = DB::table('users')
->where('users.initials', '!=', '')
->left_join('user_ratings', 'user_ratings.uid', '=', 'users.uid')
->where_in('users_ratings.rid', array(6,17,21,20))
->group_by('users.uid')
->order_by('users.name')
->get();
Tables:
Users
=======
uid name
1 John
2 Jeff
3 Cathy
Ratings
======
rid uid
1 1
2 1
2 2
3 1
4 3

The problem is when you do a left_join, the result you are going to get is multiple rows. So without the group_by clause it will return all the results you want in rows, not columns, and with the group_by it will just return the first rating (which is the expected behavior).
I would suggest you just use Eloquent ORM and set up the models and their relationships (it's a lot easier and cleaner). I'm guessing user_rating is a many-to-many pivot table? In which case you would have two models User and Rating and their relationship will be has_many_and_belongs_to. Also, the naming conventions in laravel have the pivot table in alphabetical order, so it will be called "rating_user". Look here for how to set up relationships: http://laravel.com/docs/database/eloquent#relationships
Once the models with their relationships are setup, what I would do is
$users = User::where('initials', '!=', '')->order_by('name')->get();
Then,
foreach($users as $user) {
echo "Ratings for " .$user->name . ": ";
$ratings = $user->ratings()->pivot()->where_in('rid', array(6,17,21,20))->get();
foreach($ratings as $rating) {
however you want to display the ratings here...
}
}
This may not be the most efficient way, but it should get the job done given my assumptions are true.

A quick look at the documentation reveals that the Fluent Query Builder can only do what MySQL can do, and MySQL cannot return an array to the client.
Take a look at this question for your alternatives.
If you want Laravel to fetch the ratings for you, you need to build a model.

Related

Laravel select from DB where in Collection - Laravel Nova

I have a DB, "views," with many, many entries. I also have a "Courses" table, which these views are one-many related to. In Laravel Nova, I can get a metric of all views over time for a course with some code like this:
public function calculate(Request $request)
{
return $this->countByDays($request, view::where('viewable_id', $request->resourceId));
}
In this case, viewable_id is the id of the course, and $request->resourceId gives the ID of the course to sort by. Pretty simple.
However, now things get a little difficult. I have another model called Teachers. Each Teacher can have many courses, also in a one-many relationship. How do I get a metric of views over time for all the courses that teacher teaches?
I assumed the simplest way to do this would be to create a Laravel Collection with all courses the Teacher teaches (not exactly efficient), and then select all views in the database where viewable_id matches one of the courses in that list. Of course, by posting this, I couldn't figure out how to do that.
Of course, once this is figured out, I'd love to do the same thing for Categories (though that should function in a very identical manner to Teachers, so I don't need to ask that question).
How do I get a metric of views over time for all the courses that teacher teaches?
This should be the "countByDays" of views where the viewable_id is in the list of course ids that the teacher teaches.
An SQL query statement to achieve that is given below:
select * from "views"
where "viewable_id" in (select "id" from "courses" where "teacher_id" = ?)
The Eloquent query should be similar to:
$this->countByDays($request,
view::whereIn(
'viewable_id',
Course::with('teacher')
->select('id')
->where('teacher_id', $request->resourceId)
)
);

Get Data from Multiple Tables Laravel

I am trying to build a coupon site in Laravel. Each merchant has their own deals/coupons. I have been able to print deals/coupons for a merchant on their specific pages.
Here's my query
$deals = DB::table('deals')
-> join ('merchants', 'deals.merchant_id', '=', 'merchants.merchant_id')
-> where ('merchant_url_text', $merchant_url_text)
-> get();
So far so good.
Now this is where it starts getting complex.
Each deal has 2 more pieces associated with it. Click counts and Votes associated with deals.
The click counts are in a table called clicks which records each click on the website. The click record will have a click id associated it. So I would need to get a count of clicks each deal gets.
The second piece is votes. The votes around a deal are stored in a deal_votes table. The deal_votes table has deal_id, vote (1 or 0)
How do I combine click counts and deal votes to return in the same query so that I can display the info in my view?
Do you have models and relationships set up for merchants, deals, coupons, and clicks? This is trivial if you use Eloquent models with relationships, for which the docs are here: https://laravel.com/docs/5.2/eloquent-relationships
This would look like:
$merchant = Merchant::where('merchant_url_text', $merchant_url_text)
->with('deals','deals.votes','deals.clicks')
->first();
The with() function adds all of the nested information, ie query joins, into a single query.
In your view:
#foreach($merchant->deals as $deal)
Deal: {{$deal->name}}
Clicks: {{count($deal->clicks)}}
Votes: {{$deal->votes->sum('vote')}}
#endforeach

Laravel 5.1 / Eloquent: How do I use a 3rd table to select from the second table

I have three tables: users, purchase_orders and approvals.
One purchase_order has to be approved by multiple users.
When a new purchase_order gets created, I also create 3 pending approvals belonging to that PO.
The approvals table has a field allowed_user_type that determines who can approve it.
I can't figure out, what is the Eloquent way of selecting the pending purchase orders that can be approved by a specific user, as these are determined from the approvals table.
So far I can pull the pending approvals from the approvals table for a user with the following in the User model.
public function approvals_pending()
{
return $this->hasMany('App\Approval', 'allowed_user_type', 'user_type')
->where('approved', '=', 0);
}
The question is, how do I combine this with a theoretical filter?
I mean ideally, I would love to write:
return $this->hasMany('App\PO')->whereIn('id', '=', $this->approvals_pending()->get()->po_id);
Or something like that...
Any ideas would be greatly appreciated.
OK, for anyone interested I found a solution:
It's very close to what I thought I would have to write.
The lists method basically creates a single array out of the selected field, so it can be plugged-in directly to a whereIn method like so:
return \App\PO::whereIn('id', $this->approvals_pending()->lists('po_id'));
I don't know if this is the most Eloquent way of doing this but it does work.

querying many-to-many-relationship laravel

I have a many-to-many relationship with models Competition and Season with a pivot table named competition_season.
Season->belongsToMany->Competitions->hasMany->Teams->hasMany->Players
I want to query the data of all players in a team in a specific season.
something like
\App\Player::with('team.competition.season')->where('team.competition.season.id', 2);
However since season is a collection (competition has many seasons) at this moment i can never query it like this.
Can someone point me in the right direction to properly select all players in a team in a particular season?
First, you need to add relation hasManyTrough at your model (read more about at: has-many-through)
Then, all you need is "whereHas"
$players = \App\Player::with('season')->whereHas('season', function($q){
$q->where('season.id', '=', 2);
})->get();

remove from select laravel

I'm creating a system where a club has multiple teams, and in every team can be users (users can be in multiple teams)
Now all the eloquent things work for selecting all the things :)
but now I want to generate a list of all users from the a club that are NOT in the team already
now I just normal select the users by doing the following:
$team->club->users()->lists('name','id')
This is on the team page, so first I get the club the team is from and then I get all the users, and only select the name and Id.
I've used Laravel pretty extensively over the last six months and I think what you're looking for is the "whereNotIn" functionality of Eloquent.
Here's an example, based on my application:
$user = User::whereNotIn('id', function($query) {
$query->select('id')
->from('hospital_user')
->where('hospital_user.hospital_id', '=', 54);
})->lists('email', 'id');
This could be simplified like:
$hospital = Hospital::findOrFail(54);
$users = User::whereNotIn('id', $hospital->users()->lists('user_id'))
->lists('email', 'id');
I hope my example helps. What I've done here is selected all of my users which are not in the hospital_user pivot table for the specific hospital.

Categories