仅将条件应用于一次

时间:2019-05-17 17:30:16

标签: php laravel eloquent query-builder

我正在为我的应用程序构建搜索功能。为了简化事情: 有两个表:商店和订阅

每个商店可以有多个订阅记录,订阅具有字段expires_at。现在,我假设如果存在订阅,并且商店的至少一项预订的expires_at date比now()大,则商店具有有效的订阅。

这是整个查询的条件之一。这是代码:

$shops = Shop::when($subscription, function($query, $subscription) {
    $query->doesntHave('subscriptions')->orWhereHas('subscriptions', function($q) use ($subscription, $query) {
        $query->where('expires_at', '<', now());
    });
});

它不能按预期工作,因为如果shop具有三个相关的订阅,并且其中至少有一个已过期–则假定shop没有有效的订阅(即使已订阅)。

我需要在内部或其中实现一些嵌套函数,以便按expires_at desc排序,然后限制为1,然后再传递whereexpires_at子句,但是我不知道如何实现。

我宁愿坚持使用Eloquent Query Builder,而不是DB Facade或原始SQL。

基本上,这里没有回答的是相同的问题: https://laracasts.com/discuss/channels/eloquent/latest-record-from-relationship-in-wherehas?page=1

3 个答案:

答案 0 :(得分:0)

尝试一下:

$shops = Shop::doesntHave('subscriptions')->orWhereHas('subscriptions', function ($query) {
    $query->whereDate('expires_at', '<', now());
})->get();

答案 1 :(得分:0)

尝试:

$shops = Shop::WhereHas('subscriptions')->withCount('subscriptions as 
   active_subscriptions_count' => function ($query) {
          $query->where('expires_at', '<', now());
        }])->having('active_subscriptions_count', '>=', 3)->get();

答案 2 :(得分:0)

好吧,所以在尝试一些原始sql之后,我发现了:

$query->select('shops.*')
    ->leftJoin('subscriptions', 'shops.id', 'subscriptions.shop_id')
    ->whereNull('subscriptions.id')
    ->orWhere('subscriptions.expires_at', '<', now())
    ->where('subscriptions.id', function($q) {
        $q->select('id')
            ->from('subscriptions')
            ->whereColumn('shop_id', 'shops.id')
            ->latest('expires_at')
            ->limit(1);
    });

这不仅比where子句快,而且还提供了我所需的内容–仅考虑给定商店的“最高”订阅。