Reputation: 11
I have two tables:
posts
table:
id | user_id | message
----------------------
1 | 24 | hello
2 | 96 | world
...
posts_seen
table:
id | user_id | post_id
----------------------
1 | 24 | 2
2 | 96 | 1
The second table, posts_seen
, simply tracks which posts have been "seen" (or read) by a user. For example, user #24 has seen post #2.
In my Post.php
model, I have this:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $table = 'posts';
public function seen()
{
return $this->hasOne('App\Models\PostSeen');
}
}
However, when I query posts, I want to exclude posts that have already been seen by the user. Right now, I only have this:
$posts = Post::with('seen')
->get();
I want to modify this so that, if I am user #24, the query should not return post #2 since I have already seen it.
How do I do this?
Upvotes: 1
Views: 1753
Reputation: 11
Can use whereDoesntHave
Add a relationship count / exists condition to the query with where clauses.
$posts = Post::whereDoesntHave('seen', function($query) use ($request){
$query->where('user_id', $request->user()->id);
})
->get();
Upvotes: 0
Reputation: 452
What you should do is use the method whereNotExists
in your query builder, like this:
$posts = Post::whereNotExists(function ($query) {
$query->select(DB::raw(1))
->from('posts_seen')
->whereRaw('posts_seen.user_id = posts.user_id');
})
->get();
Note that I'm also assuming that you don't need the seen
relationship anymore. If I'm wrong, you can just call the with
again.
Upvotes: 3
Reputation: 4435
You can do something like this:
First select the post ids which are seen by user identified by user_id
$posts_seen = PostSeen::where('user_id',$user_id)->get()->lists('post_id');
Then Select all the posts excluding post ids in $posts_seen
using whereNotIn()
method.
The whereNotIn method verifies that the given column's value is not contained in the given array:
Post::whereNotIn('id',$posts_seen)->get();
Upvotes: 0