Excluding pivot rows in Eloquent ORM query - laravel

(laravel 4.2)
There are four tables involved; users, posts, flags, and post_flags.
I want to retrieve every post a certain user has, and retrieve the flags set for the post, but only the flags that are set by the user in question.
For example: A post can have flags: 1,2,2,3 where flag 2 is set twice. Once by User A, once by User B. I don't want to see the flags that User B has set.
The Eloquent query in my controller:
$posts = Post::whereHas('companies', function($q) use($company_id) {
$q->where('id', '=', $company_id);
})->with('flags')->get();
The Relation in my Post model:
public function flags() {
return $this->belongsToMany('PostFlag', 'post_postflags', 'post_id', 'flag_id')
->withTimestamps()->withPivot('owner');
}
How would I achieve this using Eloquent ORM?
UPDATE
My final query, thanks to andrewtweber:
Final query
$posts = Post::whereHas('users', function($q) use($id) {
$q->where('id', '=', $id);
})->get()->load([
'flags' => function($query) use($id) {
$query->where('owner', '=', $id)->orWhere('owner', '=', 'SYSTEM');
}
]);

Use wherePivot
http://laravel.com/api/4.2/Illuminate/Database/Eloquent/Relations/MorphToMany.html
$flags = $post->flags()
->wherePivot('user_id', '=', $user_id)
->get();
Or with eager loading
$posts->load([
'flags' => function ($query) use($user_id) {
$query->wherePivot('user_id', '=', $user_id);
}
]);

Related

How to implement relationship in where condition Laravel's eloquent?

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"););
}
])

Laravel Eloquent - Having trouble querying relationship with ownership

I want to get all categories and within those categories, only items that belong to the logged in user. If there are none, the category should still be there.
This is what I tried. Still getting items from other users.
$categories = Category::parents()
->with(['lineItems' => function ($query) use($id) {
$query->where('user_id', $id);
}])->get();
Haven't been able to find anything that works. (using laravel 5.7)
Relationships
Category
public function lineItems()
{
return $this->hasMany(LineItem::class);
}
LineItems
public function category()
{
return $this->belongsTo(Category::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
I'm not sure where the ::parents() method is coming from (I can't find documentation for it anywhere; is it something you wrote?), but it seems like
$categories = Category::all()
->with(['lineItems' => function ($query) use ($id) {
$query->where('user_id', $id);
}])->get();
might work?
So, Travis's question made me think about my loop. My with was affecting my top level categories which left its children's line items without the where user. There's probably a more elegant method of doing this but this is what ended up working.
This queries the child's line items and the grandchild's line items.
$categories = Category::parents()->ordered()
->with(['children.lineItems' => function($q) use($id) {
$q->where('user_id', '=', $id);
}, 'children.children.lineItems' => function($q) use($id) {
$q->where('user_id', '=', $id);
}])->get();
Try this:
$categories = Category::parents()
->whereHas('lineItems', function ($query) use($id) {
$query->where('user_id', $id);
})->get();

Laravel, where, orwhere in main table an pivot table

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"

Eloquent - How should I make a condition in a join table

I have a tournament table.
Each tournament hasMany Championships.
I want to get the tournament that match the championshipID = 333.
So, I do it :
$tournament = Tournament::with([
'championships' => function ($query) use ($request) {
$query->where('id', '=', 333);
},
'championships.settings',
'championships.category',
'championships.tree.user1',
'championships.tree.user2',
'championships.tree.user3',
'championships.tree.user4',
'championships.tree.user5'
])->first();
Example of 1 of my relations:
public function settings()
{
return $this->hasOne(ChampionshipSettings::class);
}
Tell me if you need all, to post it.
But as I put 1 eager loading relationship, I get all my tournaments instead of getting just one.
What Am I missing???
I think you're looking for whereHas() which will allow you to filter a model based on a related model's constraints. You should also use a subquery for the nested constraints if you're getting the related model more than once to avoid query duplication like:
$tournament = Tournament::whereHas('championships', function($query) use ($championshipId) {
return $query->where('id', $championshipId);
})
->with(['championships' => function ($query) use ($request) {
$query->where('id', '=', 333)
->with([
'settings',
'category',
'tree' => function($query) {
return $query->with('user1', 'user2', 'user3', 'user4', 'user5');
}]);
}])
->first();

Laravel 4 Eager Loading constraints

I want to get all Items (topics) WITH their comments, if comments user_id = $id. I try something like this, but it isn't working. So if Item hasn't got any comment with user_id = $id, then I don't need this Item.
In DiscussionsItem model I have methode:
public function discussionsComments() {
return $this->hasMany('DiscussionsComment', 'discussionsitem_id');
}
My query in controller is like this:
$items = DiscussionsItem::whereBrandId($brand_id)
->whereBrandCountryId($country_id)
->with(['discussionsComments' => function($query) use ($id) {
$query->where('user_id', '=', $id);
}])
->whereHas('discussionsComments', function($query) use ($id) {
$query->where('user_id', '=', $id);
})
->with(['views' => function($query) use ($id) {
$query->where('user_id', $id)->count();
}])
->orderBy('created_at', 'DESC')->get();
My problem is that I get items with comments, where comments user_id != $id.
P.S. I need to take 5 comments, but I cant imagine how to do that, because ->take(5) in my eager load is not working.
You can do a custom scope, or just limit the amount returned by your relation:
public function discussionsComments() {
return $this->hasMany('DiscussionsComment', 'discussionsitem_id')
->latest()
->take(5);
}

Resources