This is my simple db schema. Now in my group table i have 'group_A' and 'group_B'. In questions table i have 10 questions 5 for group_A and 5 for group_B. Users table is one user with ID = 1. What i try to do is get data like this:
SELECT answer
FROM answers
JOIN questions q ON (q.id = answer.question_id)
JOIN group g ON (g.id = q.group_id)
WHERE user_id = 1 AND g = 'group_A'
I have model in users class and i would like create method to get answers depend from group:
public function getAnswers($group) {
return $this->hasMany('App\Answers', 'question_id', 'id');
}
How can i get this in that method ? Should i create method group in questions class ?
Not sure about how to define such relation in model which takes input parameter but you could define a scope in your model to get the answers filtered by group like
class Answer extends Model {
public function user()
{
return $this->belongsTo('App\User');
}
public function question()
{
return $this->belongsTo('App\Question');
}
public function scopeGroup($query, $name)
{
return $query->whereHas('question.group', function($q) use($name){
$q->where('name', '=', $name);
});
}
}
I assume in answers model you have defined relationship for question and similarly in question model you have defined relationship for group model.
In query builder you could write it as
$answers = Answer::group('group_A')
->whereHas('user', function($q) use($userid){
$q->where('id', '=', $userid);
})->get();
Or you could apply filter on eager loaded relations as
$users = User::with(['answers' => function($query)
{
$query->whereHas('question.group', function($q){
$q->where('name', '=', 'group_A');
});
}])->get();
If you already have user object you can get answers for specific group as
$answers = $user->answers()
->whereHas('question.group', function($q){
$q->where('name', '=', 'group_A');
})->get();
Related
I have two models with relations as defined below
Order
public function owner()
{
return $this->belongsTo(User::class, 'owner_id');
}
User
public function company(){
return $this->belongsTo(Company::class, 'company_id');
}
company table have 'title' field.
what I want is to get all the orders sorted/order by company title. I've tried different solution but nothing seems to work. Any help or hint would be appreciated.
Recent solution that I tried is
$query = OrderModel::whereHas('owner', function($q) use ($request){
// $q->orderBy('owner');
$q->whereHas('company',function ($q2) use ($request){
$q2->orderBy('title',$request->get('orderByDirection') ?? 'asc');
});
});
but I am not getting user and company relation in query results. also the result remains same for 'ASC' and 'DESC' order.
You could sort the query after adding join like:
return Order::join('users', 'users.id', '=', 'owner_id')
->join('companies', 'companies.id', '=', 'users.company_id')
->orderBy('companies.title')
->select('orders.*')
->get();
You can define new relations in User and Company models.
User
public function orders()
{
return $this->hasMany(Order::class);
}
Company
public function users()
{
return $this->hasMany(User::class);
}
Now you can fetch companies that are in asc order and with the use of relation, you can fetch users and orders. So the ORM like be,
$companies = Company::with('users.orders')->orderBy('title', 'ASC')->get();
So these are the company-wise orders. You can use this too.
I have two tables:
Students
Results
The two tables have one to may relationship.
Student model:
public function results()
{
return $this->hasMany('App\Result');
}
Result model:
public function student()
{
return $this->belongsTo('App\Student');
}
In the students table I have a field called average_score.
How can I execute the following query, this is not working it says "Undefined property: Illuminate\Database\Query\Builder::$student":
$data = Result::with('student')->where('score', '>=', function($q){
$average_score = $q->student->average_score;
return $average_score;
})->get();
In order to get the results that are only higher or equal to than the "average_score".
If score and average_score are columns of the same table (student), try this;
$data = Result::with(['student' => function ($query) {
$query->whereColumn('score', '>=', 'average_score');
}])->get();
If score and average_score are columns of the different tables, try this;
$data = Result::with('student')->whereHas('student', function($q) {
$q->whereColumn('students.average_score', '<=', 'results.score');
})->get();
You can use whereHas to find those results:
$data = Result::with('student')->whereHas('student', function($q) {
$q->whereColumn('average_score', '<=', 'Results.score');
})->get();
get value from column Results.average_score then compare to student.score:
Result::with([
'student' => function($query) {
$query->where("score",">=", "Results.average_score"););
}
])
I am using 2 tables upon displaying my users in my users>index.blade
these 2
USER table
and COLLECTOR_MEMBERS table
The result is this
Now my problem is I want to connect to the other table called
COMMISSIONS table
to achieve this result
MODELS
COMMISSIONS Model
USER
COLLECTOR MEMBER
USER Controller index function
public function index(Request $request)
{
$users = User::all();
$admins = User::whereHas('roles', function ($q) {
$q->where('roles.name', '=', 'admin');
})->get();
$collectorList = User::whereHas('roles', function ($q) {
$q->where('roles.name', '=', 'collector');
})->with('collectorList')->get();
$borrowers = User::whereHas('roles', function ($q) {
$q->where('roles.name', '=', 'borrower');
})->get();
$userProfile = Auth::user()->id;
if (Auth::User()->hasRole(['borrower','collector'])){
return redirect('dashboard/profile/'.$userProfile);
}
return view('dashboard.users.index', compact('users','profile'))
->with('admins',$admins)
->with('borrowers',$borrowers)
->with('collectorList',$collectorList);
// ->with('collectorBorrowers',$collectorBorrowers);
}
How wan I display the commission_amount column from commissions table? to make my list like this
You could use sum aggregate function, your code should look like this.
$collectorList = User::whereHas('roles', function ($q) {
$q->where('roles.name', '=', 'collector');
})->with(['collectorCommission' => function($query) {
$query->sum('commission_amount');
}])->get();
Assuming that you have this relationship in your user model
public function collectorCommission() [
return $this->hasMany('App\Commissions', 'user_id');
}
You cant use belongsToMany relationship since this relationship
requires you an intermediary table in your second argument.
You should use hasMany relationship considering that one user has many commissions.
I have two tables with belongsToMany relation: message_topics and users
The pivot table is message_topics_users and contains 2 columns: message_id and user_id.
In table message_topics, I have a field called sender_id
I'm trying to write the correct eloquent syntax to get all the records:
where message_topics.sender_id = $user_id
OR Message_topics_users.receiver_id = $user_id
I tried many things, like for instance:
$topics = MessageTopic::where('sender_id', $user_id)
->wherePivot('receiver_id', $user_id)->orderBy('sent_at','desc')->get();
Any idea?
You can use the whereHas method (or in this case the orWhereHas method):
$topics = MessageTopic::where('sender_id', $user_id)
->orWhereHas('users', function ($query) use ($user_id) {
$query->where('id', $user_id);
})
->orderBy('sent_at', 'desc')
->get();
I'm assuming you have two relationships from the topics? Since it's too arbitrary to use both columns and the same relationship... Like this
//On your MessageTopic model
public function sender(){
return $this->belongsToMany('App\User', 'message_topics_users', 'message_id', 'sender_id');
}
public function receiver(){
return $this->belongsToMany('App\User', 'message_topics_users', 'message_id', 'receiver_id'));
}
Then you can use whereHas and orWhereHas like this:
//Again assuming you have your User model loaded as $user
$topics = App\Topic::whereHas('sender', function($q) use($user){
$q->where('sender_id', '=', $user->id);
})
->orWhereHas('receiver', function($q) use($user){
$q->where('receiver_id', '=', $user->id
})
->orderByDesc('sent_at')
->get();
whereHas and orWhereHas both query the model (MessageTopic in this case) checking for the existence of the specified relationship (App\Topic::whereHas('sender')...). They also allow you to pass the constraint that you're looking for (function($q) use($user){ $q->... })
So it is basically saying "Give me ONLY the MessageTopics that have a Sender or Receiver with the id $user->id"
In Laravel we can setup relationships like so:
class User {
public function items()
{
return $this->belongsToMany('Item');
}
}
Allowing us to to get all items in a pivot table for a user:
Auth::user()->items();
However what if I want to get the opposite of that. And get all items the user DOES NOT have yet. So NOT in the pivot table.
Is there a simple way to do this?
Looking at the source code of the class Illuminate\Database\Eloquent\Builder, we have two methods in Laravel that does this: whereDoesntHave (opposite of whereHas) and doesntHave (opposite of has)
// SELECT * FROM users WHERE ((SELECT count(*) FROM roles WHERE user.role_id = roles.id AND id = 1) < 1) AND ...
User::whereDoesntHave('Role', function ($query) use($id) {
$query->whereId($id);
})
->get();
this works correctly for me!
For simple "Where not exists relationship", use this:
User::doesntHave('Role')->get();
Sorry, do not understand English. I used the google translator.
For simplicity and symmetry you could create a new method in the User model:
// User model
public function availableItems()
{
$ids = \DB::table('item_user')->where('user_id', '=', $this->id)->lists('user_id');
return \Item::whereNotIn('id', $ids)->get();
}
To use call:
Auth::user()->availableItems();
It's not that simple but usually the most efficient way is to use a subquery.
$items = Item::whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
})
->get();
If this was something I did often I would add it as a scope method to the Item model.
class Item extends Eloquent {
public function scopeWhereNotRelatedToUser($query, $user_id)
{
$query->whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
});
}
}
Then use that later like this.
$items = Item::whereNotRelatedToUser($user_id)->get();
How about left join?
Assuming the tables are users, items and item_user find all items not associated with the user 123:
DB::table('items')->leftJoin(
'item_user', function ($join) {
$join->on('items.id', '=', 'item_user.item_id')
->where('item_user.user_id', '=', 123);
})
->whereNull('item_user.item_id')
->get();
this should work for you
$someuser = Auth::user();
$someusers_items = $someuser->related()->lists('item_id');
$all_items = Item::all()->lists('id');
$someuser_doesnt_have_items = array_diff($all_items, $someusers_items);
Ended up writing a scope for this like so:
public function scopeAvail($query)
{
return $query->join('item_user', 'items.id', '<>', 'item_user.item_id')->where('item_user.user_id', Auth::user()->id);
}
And then call:
Items::avail()->get();
Works for now, but a bit messy. Would like to see something with a keyword like not:
Auth::user()->itemsNot();
Basically Eloquent is running the above query anyway, except with a = instead of a <>.
Maybe you can use:
DB::table('users')
->whereExists(function($query)
{
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
Source: http://laravel.com/docs/4.2/queries#advanced-wheres
This code brings the items that have no relationship with the user.
$items = $this->item->whereDoesntHave('users')->get();