【问题标题】:Laravel eloquent belongs to many query returns entries multiple timeLaravel eloquent 属于很多查询多次返回条目
【发布时间】:2021-03-02 20:12:50
【问题描述】:

我有一个productsusersproducts_marks 表。用户可以“标记”产品。当他们标记一个产品时,数据库会将user_idproduct_id 存储在products_marks 表中。

标记基本上意味着用户想要观看此产品并拥有一个关注列表。当然,我想向用户展示他标记的所有产品。这意味着我必须获取products_marks 表中的user_id 与实际用户匹配的所有产品。不过,我对此也有一些额外的要求。

产品确实有post_status_id。这表示产品发布、离线、审核中、待定等的天气。标记的产品仅应在产品也在线时向用户呈现。 但是如果用户标记了他自己发布的产品,因此他是该产品的所有者,他也应该在该产品发布时看到该产品AND等待.

这在大多数情况下也有效。我已经对此有一个雄辩的查询。但是现在我发现了一个奇怪的问题。一位用户向我报告说,他在他的关注列表中两次看到一个产品。我已经为这个用户运行了 SQL 查询,是的,数据库返回了两次产品!为什么这个?每个产品只能获得一次,我必须进行哪些更改?

用户模型:

/** 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;
}

查询为 SQL 语句:

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

我还创建了一个db fiddle here,您可以在其中运行此SQL 语句并看到数据库两次返回user_id 13 的条目。但这是为什么呢?为什么只是有时?

看起来当多个用户标记同一个产品时,我会多次获得它。正如您在小提琴中看到的那样,ID 为 43 的产品被标记了两次!

诚挚的问候,谢谢!

【问题讨论】:

  • ->join() 显然会在 1toN 中产生重复,所以看看你的期望是什么
  • 好吧,我想获取 user_id = 13 的所有产品,并且产品是发布 (1) 或用户 (13) 是产品的所有者。如果是这样,产品也可能是待处理的 (4)。但我不想多次获得一个条目
  • 你发布的那些函数在用户模型里面?
  • 是的。因为我想要该特定用户@Berto99 的所有标记产品

标签: php mysql laravel join eloquent


【解决方案1】:

大概是这样的:

/** Eloquent Query */
public static function markedProductsPaginated(User $user){
    $products = $user->products()->withPivot('created_at')->select('products.*')
        ->whereHas('marks', function ($query) use ($user) {
            $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;
}

【讨论】:

  • 这将返回以下错误(orderBy 不知道 created_at)SQLSTATE[42S22]: Column not found: 1054 Unknown column 'products_marks.created_at' in 'order Clause' (SQL: select @ 987654322@.* from products where products.user_id = 1 and products.user_id 不为空且存在(从users 内部连接users.@987 上选择* @ = products_marks.user_id 其中products.id = products_marks.product_id 和 ((page_status_id = 1) 或 (page_status_id = 4 和 products.@987654 1))) 按products_marks.created_at desc limit 10 offset 0) 排序
  • 知道如何解决这个问题吗?这就是我选择join 的原因
  • @Jan 试试看,我已经加了->withPivot('created_at'),否则请贴出laravel生成的SQL(应该有->toSql()方法)
猜你喜欢
  • 1970-01-01
  • 2017-07-30
  • 2021-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-19
  • 2013-06-19
相关资源
最近更新 更多