Применять там, где условие только в одном случае - PullRequest
0 голосов
/ 17 мая 2019

Я создаю функцию поиска для моего приложения.Для упрощения: есть две таблицы: магазины и подписки

Каждый магазин может иметь несколько записей подписки, поле подписки имеет expires_at.Теперь я предполагаю, что магазин имеет активную подписку, если подписка существует, и хотя бы одна из дат expires_at подписки магазина больше, чем now ().

Это одно из условий для всего запроса.Вот код:

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

Он не работает должным образом, потому что, если у магазина есть три связанных подписки, и по крайней мере одна из них истекла - это предполагает, что у магазина нет активной подписки (даже если у него есть).

Мне нужно было бы реализовать некоторую вложенную функцию внутри или где, я думаю, чтобы она сортировалась по expires_at desc, а затем ограничивалась одним и только потом передавала бы выражение expires_at, однако я понятия не имею, как.

И мне скорее нужно придерживаться Eloquent Query Builder, а не фасада БД или неформатированного sql.

По сути, это та же проблема, что здесь не был дан ответ: https://laracasts.com/discuss/channels/eloquent/latest-record-from-relationship-in-wherehas?page=1

Ответы [ 3 ]

0 голосов
/ 18 мая 2019

попробуйте это:

$shops = Shop::WhereHas('subscriptions')->withCount('subscriptions as 
   active_subscriptions_count' => function ($query) {
          $query->where('expires_at', '<', now());
        }])->having('active_subscriptions_count', '>=', 3)->get();
0 голосов
/ 18 мая 2019

Хорошо, так что после некоторых попыток в raw 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);
    });

Это не только быстрее, чем пункт, где существует, но также дает мне то, что мне нужно - только самая «высокая» подписка наданный магазин находится на рассмотрении.

0 голосов
/ 17 мая 2019

Попробуйте это:

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