仅将 where 条件应用于一次

Apply where condition only to one occurrence

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

每个店铺可以有多个订阅记录,订阅有字段expires_at。现在,我假设如果订阅存在并且商店的至少一个订阅 expires_at 日期大于现在()。

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

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

它没有按预期工作,因为如果商店有三个相关订阅并且其中至少一个已过期 – 它假定商店没有活动订阅(即使它有)。

我需要在内部或 whereHas 实现一些嵌套函数,我想,按 expires_at desc 排序,然后限制为一个,然后才传递 where expires_at 子句,但是我已经不知道如何。

而且我宁愿坚持使用 Eloquent Query Builder 而不是 DB facade 或原始 sql。

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

试试这个:

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

试试这个:

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

好的,所以在原始 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 exists 子句更快,而且还提供了我需要的东西——仅考虑给定商店的 "highest" 订阅。