I know, we can do this in the controller:
User::with('post')->get();
It will get every user's post from the database, based on users.id.
But the problem is, I want to do this:
User::with(['post' => function($query) {
# Throw users.id here...
}])->get();
How to do that?
You should get the users first, and then load related posts with a separate query and merge them manually.
$users = User::get();
$posts = Post::whereIn('user_id', $users->pluck('id'))->get(); // Get your additional data in this query
$users->each(function ($user) use ($posts)
{
$user->posts = $posts->where('user_id', $user->id);
});
Note: I did not test the code above. It's just an example to show you how to accomplish what you are trying to do.
Related
I have two models:
User
Post
Comment
User has many posts. Post has many comments and Comment belongs to a Post. That is simple.
Now I want to load all the post of authenticated user with its comments if the post has comment created today. If the post doesn't have comment today, it will not be loaded. The posts will also be paginated. How to build the query in laravel eloquent?
I tried something like this:
Auth::user()->posts->load(['comments' => function($query) {
$query->where('created_at',Carbon::today());
}]);
The issue in your query is that you are already executing it. Check this part:
Auth::user()->posts->...
^^^^^^^^
You are accessing the relationship as a property. When you do that the query is already being executed. What you need to do is to limit the results before executing the query. To do that, access the relationship but as a function, this way you receive an instance of the Query Builder to apply all your constrains before executing the query (with ->get() in this example). To limit a relationship with conditions, you can make use of the whereHas():
$posts = Auth::user()->posts()->whereHas(['comments' => function($query) {
$query->where('created_at', '>=', today());
}])
->get();
In the above code, you'll receive all the posts that has at least one comment today. But you are yet to receive the comments attached to them. To do so, you need to eager load the relationship with the with() method.
$posts = Auth::user()->posts()->whereHas('comments', function($query) {
$query->where('created_at', '>=', today());
})
->with('comments') // <--
->get();
That should do it. But given that you need the elements paginated, exchange the get() with paginate() method:
$posts = Auth::user()->posts()->whereHas('comments', function($query) {
$query->where('created_at', '>=', today());
})
->with('comments')
->paginate(15); // <---
Hey guys I have a query that looks like this
$query = Transaction::with(['customer', 'merchant', 'batch'])
->select(sprintf('%s.*', (new Transaction)->table));
I need to filter the transaction based on the iso_id that belons to the current user logged in.
$query = Transaction::with(['customer', 'merchant', 'batch'])
->select(sprintf('%s.*', (new Transaction)->table))
->where('merchant.iso_id', '=', auth()->user()->isIso());
The iso_id I need to compare to, is inside the merchant table
auth()->user()->isIso() returns the correct iso_id if true or sends false if not
So my first try at this was to use where('merchant.iso_id', '=', auth()->user()->isIso())
But that returns that the column does not exist because for some reason, it's not switching from the transaction model to the merchant one.
I am not sure how to use the stuff inside with() as a selector for my where()
Any help would be appreciated!
Try using whereHas to add the constraint:
$query = Transaction::with(['customer', 'batch'])
->whereHas('merchant', function ($q) {
$q->where('iso_id', auth()->user()->isIso());
})
->select(sprintf('%s.*', (new Transaction)->table))
->get();
Im trying to make a query using whereHas with eloquent. The query is like this:
$projects = Project::whereHas('investments', function($q) {
$q->where('status','=','paid');
})
->with('investments')
->get();
Im using Laravel 5.2 using a Postgres driver.
The Project model is:
public function investments()
{
return $this->hasMany('App\Investment');
}
The investments model has:
public function project() {
return $this->belongsTo('App\Project');
}
The projects table has fields id,fields...
The investments table has the fields id,project_id,status,created_at
My issue is that the query runs and returns a collection of the projects which have at least one investment, however the where clause inside the whereHas is ignored, because the resulting collection includes investments with status values different than paid.
Does anyone has any idea of what is going on?
I believe this is what you need
$projects = Project::whereHas('investments', function($q) {
$q->where('status','=','paid');
})->with(['investments' => function($q) {
$q->where('status','=','paid');
}])->get();
whereHas wil check all projects that have paid investments, with will eagerload all those investments.
You're confusing whereHas and with.
The with method will let you load the relationship only if the query returns true.
The whereHas method will let you get only the models which have the relationship which returns true to the query.
So you need to only use with and not mix with with whereHas:
$projects = Project::with(['investments' =>
function($query){ $query->where('status','=','paid'); }])
->get();
Try like this:
$projects = Project::with('investments')->whereHas('investments', function($q) {
$q->where('status','like','paid'); //strings are compared with wildcards.
})
->get();
Change the order. Use with() before the whereHas(). I had a similar problem few weeks ago. Btw, is the only real difference between the problem and the functional example that you made.
Assumed we've got users, friends and restaurants. Don't want to go to deep into the Model and relationship setup.
While me as a user is logged in: How can I get all friends who are "customers" of the restaurant?
I've got this and it's already working:
$friends = array_dot(Auth::user()->friends()->select('users.id')->get());
$customers = Restaurant::with(['users' => function($query) use($friends) {
$query->whereIn('users.id', $friends);
}])->find(restaurant_id);
But is this even possible with a single query?
It sounds like you want to find all of your friends that have a relationship to the restaurant. If so, you're looking for whereHas(). General idea:
$restaurantId = 1;
$user = Auth::user();
$friendCustomers = $user->friends()->whereHas('restaurant', function ($query) use ($restaurantId) {
$query->where('id', $restaurant_id);
})->get();
You can read more about querying relations, and whereHas, here.
I've got a situation where I've got Posts, Users and Comments.
Each comment stores a post_id and a user_id. What I want to do is get all of a user's comments on a particular post, so that I can do a call like this:
$comments = Auth::User()->comments(post_id=x)->text
(where I know what x is)
I have:
User->HasMany(comments)
Comments->HasOne(User)
Comments->HasOne(Project)
Project->HasMany(comments)
I feel like there needs to be a where or a has or a wherehas or something thrown in.. the best I can manage is that I pull Auth::User()->comments into an array and then search through the array until I find the matching post ID.. that seems wasteful.
with doesn't apply any join, so you can't reference other table.
You can use this:
// User model
public function comments()
{
return $this->hasMany('Comment');
}
// Comment model
public function scopeForPost($query, $postId)
{
$query->where('post_id', $postId);
}
// then you can do this:
Auth::user()->comments()->forPost($postId)->get();
Alternatively you can eager load comments with constraint:
User::with(['comments' => function ($q) use ($postId) {
$q->where('post_id', $postId);
}])->find($someUserId);
// or exactly the same as above, but for already fetched user:
// $user .. or
Auth::user()->load(['comments' => function ($q) use ($postId) {
$q->where('post_id', $postId);
}]);
// then you can access comments for $postId just like this:
Auth::user()->comments; // collection
When you need to filter your relations, you just have to do it in your Eloquent query:
$data = User::with('posts', 'comments')
->where('users.id', Auth::User()->id)
->where('posts.id', $postID)
->get();
Then you can
foreach($data->comments as $comment)
{
echo $comment->text;
}
Your Comments table would have foreign keys Post_Id and User_ID
To Access all the comments of a particular post from a particular user , can you try this way?
Comment::select('comments.*')
->where('comments.user_id', Auth::user()->id)
->leftJoin('posts','posts.id','=','comments.post_id')
->leftJoin('users','users.id','=','comments.user_id')
->get();
Am sure there is better way to achieve it, but this should give you desired results.
Note use aliases if you have conflicting column names
Let me know if this worked.