I have a products, users and products_marks table. Users can "mark" products. When they mark one product the database stores the user_id and the product_id in the products_marks table.
Marks basically mean a user wants to watch this product and has a watchlist. Of course I want to show the user all products he has marked. This means I have to get all products where the user_id in the products_marks table matches the actually user. However, I have some extra requirements to this as well.
Products do have a post_status_id. This represents weather the product is publish, offline, in review, pending, etc. The marked products should only be represented to the user if the product is also online. BUT if the user has marked a product which he has posted by himself, so he is the owner of the product, he should also see this product when it is publish AND pending.
This also works in most cases. I already have an eloquent query for this. But now I have found a strange problem. A user reported me that he sees one product two times in his watchlist. I have run the SQL query for exactly this user and yes, the database is returning the product two times! Why this? What do I have to change in order to get each product only once?
User model:
/** Relationship */
public function markedProducts(){
return $this->belongsToMany('App\Models\Product', 'products_marks');
}
/** Eloquent Query */
public static function markedProductsPaginated(User $user){
$products = Product::select('products.*')
->join('products_marks', 'products_marks.product_id', '=', 'products.id')
->whereHas('marks', function ($query) use ($user) {
$query->where(function($query) use ($user){
$query->where('products_marks.user_id', $user->id);
});
$query->where(function($query){
$query->where('page_status_id', PageStatus::getIdByStatus('publish'));
});
$query->orWhere(function($query) use ($user){
$query->where('page_status_id', PageStatus::getIdByStatus('pending'))
->where('products.user_id', $user->id);
});
})
->orderBy('products_marks.created_at', 'desc')
->paginate(10);
$products->loadCount('allPublishedComments');
return $products;
}
Query as SQL statement:
select `products`.* from `products` inner join `products_marks` on `products_marks`.`product_id` = `products`.`id` where exists (select * from `users` inner join `products_marks` on `users`.`id` = `products_marks`.`user_id` where `products`.`id` = `products_marks`.`product_id` and ((`products_marks`.`user_id` = 19) and (`page_status_id` = 1) or (`page_status_id` = 4 and `products`.`user_id` = 3))) order by `products_marks`.`created_at` desc limit 10 offset 0
I have also created a db fiddle here where you can run this SQL statement and see that the database is returning the entry for the user_id 13 two times. But why is that? And why only sometimes?
It looks like when multiple users mark the same product I get it multiple times back. As you can see in the fiddle the product with the id 43 got marked two times!
Kind regards and thank you!