Все разработчики, рано или поздно, начинают понимать что стандартными средствами ORM библиотеки невозможно реализовать сложные и удобные запросы.

То тут, мы не знаем как написать простейших запрос для подсчёта суммы, без вынимания всех значений, то там, мы не можем составить нетривиальное условие.

В большинстве случаев, кроме удобного доступа к данным, ORM библиотеки доставляют нам головную боль с составлением сложных запросов и огромное количество избыточных выборок.

Сегодня я хочу рассказать, как мы можем обойти часть сложностей и упростить себе работу и, возможно, снизить нагрузку на сервер, используя ORM Jelly.

Выбираем только нужные нам поля

Для указания какие поля нам нужно возратить в кортеже, можно использовать функцию select()

Например:

// Простая выборка только нужных полей
Jelly::select('user')
        ->select('id','name')
        -execute();

// Выбираем все поля
Jelly::select('user')
        ->select('*')
        -execute();

// Суммируем значения по колонке
Jelly::select('transactions')
        ->select('title', DB::expr("SUM('money') AS money"))
        -execute();

// Выбираем все колонки из одной таблицы, и избранные из другой
Jelly::select('user')
        ->select(DB::expr('`users`.*'), DB::expr("`providers`.`id` AS provider_id"))
        -execute();

Тут важно помнить, что если какие-то из полей в кортеже у нас не были описаны в модели, то и доступ к ним мы получить привычным способом не сможем.
Для этого нам нужно использовать функцию get('field')

Как-то так:

// Суммируем значения по колонке
$transactions = Jelly::select('transactions')
        ->select('title', DB::expr("SUM('money') AS money"))
        ->execute();

// Выводим сумму
foreach ($transactions as $transaction) {
    echo $transaction->title . " " . $transactions->get('money');
}

То что нужно знать

Конечно же, вы должны уже знать как можно группировать условия логически и умеете пользоваться операторами JOIN и WITH (про них описано в официальной справке, если что).

Например вот этот поток сознания вам поможет сориентироваться в обстановке

$builder = Jelly::select('users')
        ->join('provider', 'left')
        ->on('provider.user_id', '=', 'user.id')
        ->on('provider.name', 'LIKE', 'NBN%')
        ->where('date_reg', '>', '2010-01-01')
        ->and_where('active', '=', 1)
        ->or_where_open()
        ->where('admin', '=', 1)
        ->or_where_close()
        ->execute();

До того как вы вызовете execute() или load() вы всегда можете посмотреть что у нас получается в билдере запросов. Для этого его можно просто вывести на печать.

$builder = Jelly::select('users')
        ->where('date_reg', '>', '2010-01-01');

// Выводим получившийся запрос
print $builder;

$users = $builder->execute();

Так же, важно знать что код обёрнутый DB::expr('code') не обрабатывается билдером. Что позволяет нам транслировать в него прямые куски SQL кода.

Подзапросы

Теперь можно попробовать составить что-то необычное, например подзапросы. Внимание, лучше сесть :)

$subquery = Jelly::select('price')
    ->select(DB::expr('SUM(price.spec) AS `spec`'))
    ->where('providers.id', '=', DB::expr('`price`.`provider_id`'))
    ->and_where('price.group_id', '=', DB::expr('`groups`.`group_id`'));
            
$builder = Jelly::select('user')
    ->select('`provider`.*', DB::expr('('.$subquery . ') AS `spec`'))
    ->distinct(TRUE)
    ->order_by('spec', 'DESC')
        ->execute();

Этот код не обладает красотой и теми плюшечками ORM которые нам предоставлены из коробки, но именно этот код позволяет писать гибкие запросы.