Giter VIP home page Giter VIP logo

bitrix-orm.examples's Introduction

Прочитав статью Алексея Валеева понимаешь насколько не хватает типовых примеров работы с ORM в BitrixFramework. Пополним коллекцию примеров с неочевидной логикой.

Пример 1. Джоин не пустой таблицы без дублей.

Выберем инфоблоки с кодом news у которых есть хотя бы один элемент.

При этом в выборке каждая строка должна соответствовать уникальному инфоблоку, т.е. инфоблоки в выборке не должны дублироваться.

$query = new \Bitrix\Main\Entity\Query(Bitrix\Iblock\IblockTable::getEntity());
$query
    ->registerRuntimeField('element', [
            'data_type' => 'Bitrix\Iblock\ElementTable',
            'reference' => [
                '=this.ID' => 'ref.IBLOCK_ID',
            ],
        ]
    )
    //регистрируем поле с минимальным ID эл-та (нам не важно какой именно этот элемент, важно есть ли в принципе минимальный ID или нет)
    ->registerRuntimeField('min_element_id', [
        'data_type'=>'integer',
        'expression' => ['MIN(%s)', 'element.ID']
    ])
    ->setSelect([
        'ID',
    ])
    //фильтруем
    ->setFilter([
        '!min_element_id' => false, 
        'CODE' => 'news'
    ])
    //группируем по ID инфоблока
    ->setGroup([
        'ID',
    ]);

Наступил на грабли в строке

'expression' => ['MIN(%s)', 'element.ID']

тут нужно быть внимательным.

Например, если указать

'expression' => ['MIN(element.ID)']

эта конструкция работать не будет т.к. в условие HAVING sql-запроса попадет именно строка MIN(element.ID).

И по скольку битрикс использует свои алиасы для полей и таблиц - таблица element не будет найдена. Соответственно для того чтобы битрикс корректно заменил element.ID на нужный алиас - это поле необходимо передавать вторым элементом в массиве expression.

Эту концепцию важно уловить, т.к. ее же будем использовать в последующих примерах.

Пример 2. IN с логикой AND.

Допустим нам нужно выбрать инфоблоки у которых есть элементы с CODE = 'new' ИЛИ CODE = 'hot' ИЛИ CODE = 'exclusive'. Задача довольно легко решается передачей массива в фильтр:

$query = new \Bitrix\Main\Entity\Query(Bitrix\Iblock\IblockTable::getEntity());
$query
    ->registerRuntimeField('element', [
            'data_type' => 'Bitrix\Iblock\ElementTable',
            'reference' => [
                '=this.ID' => 'ref.IBLOCK_ID',
            ],
        ]
    )
    //посчитаем количество найденых типов элементов
    //обратите внимание на DISTINCT - указывает на то что нужно считать не повторяющиеся символьные коды
    ->registerRuntimeField('COUNT_ELEMENT_CODES_VARIANTS', [
            'data_type' => 'integer',
            'expression' => ['COUNT(DISTINCT %s)', 'element.CODE'],
        ]
    )
    ->setSelect([
        'ID',
        'COUNT_ELEMENT_CODES_VARIANTS',
    ])
    ->setFilter([
        'element.CODE' => ['new', 'hot', 'exclusive']
    ]);

Но что если нужно выбрать только те инфоблоки, у которых есть элементы И с CODE = 'new' И с CODE = 'hot' И с CODE = 'exclusive' ? Получается некий IN но с логикой AND... Для этого нам нужно добавить в фильтр условие что количество уникальных символьных кодов элементов всегда должно быть = 3 ('new', 'hot', 'exclusive').

$query = new \Bitrix\Main\Entity\Query(Bitrix\Iblock\IblockTable::getEntity());
$query
    ->registerRuntimeField('element', [
            'data_type' => 'Bitrix\Iblock\ElementTable',
            'reference' => [
                '=this.ID' => 'ref.IBLOCK_ID',
            ],
        ]
    )
    ->registerRuntimeField('COUNT_ELEMENT_CODES_VARIANTS', [
            'data_type' => 'integer',
            'expression' => ['COUNT(DISTINCT %s)', 'element.CODE'],
        ]
    )
    ->setSelect([
        'ID'
    ])
    //фильтруем по количеству уникальных кодов
    ->setFilter([
        'element.CODE' => ['new', 'hot', 'exclusive'],
        '=COUNT_ELEMENT_CODES_VARIANTS' => 3
    ]);

Пример 3. Джоин по нескольким условиям.

Выберем инфоблоки у которых количество элементов с кодом hot не меньше 3, а с кодом new не менее 5.

$query = new \Bitrix\Main\Entity\Query(Bitrix\Iblock\IblockTable::getEntity());
$query
    //джоиним элементы с кодом hot
    ->registerRuntimeField('HOT_ELEMENT', [
            'data_type' => 'Bitrix\Iblock\ElementTable',
            'reference' => [
                '=this.ID' => 'ref.IBLOCK_ID',
                //добавим условие что нам нужны элементы с кодом hot
                '=ref.CODE' => new Bitrix\Main\DB\SqlExpression('?', 'hot'),
            ],
        ]
    )
    //считаем количество элементов с кодом hot
    ->registerRuntimeField('HOT_ELEMENTS_COUNT', [
        'data_type'=>'integer',
        'expression' => ['COUNT(%s)', 'HOT_ELEMENT.ID']
    ])
    //джоиним элементы с кодом new
    ->registerRuntimeField('NEW_ELEMENT', [
            'data_type' => 'Bitrix\Iblock\ElementTable',
            'reference' => [
                '=this.ID' => 'ref.IBLOCK_ID',
                //добавим условие что нам нужны элементы с кодом new
                '=ref.CODE' => new Bitrix\Main\DB\SqlExpression('?', 'new'),
            ],
        ]
    )
    //считаем количество элементов с кодом new
    ->registerRuntimeField('NEW_ELEMENTS_COUNT', [
        'data_type'=>'integer',
        'expression' => ['COUNT(%s)', 'NEW_ELEMENT.ID']
    ])
    //выбираем ID инфоблока, кол-во hot и new элементов
    ->setSelect([
        'ID',
        'HOT_ELEMENTS_COUNT',
        'NEW_ELEMENTS_COUNT',
    ])
    //фильтруем
    ->setFilter([
        '>HOT_ELEMENTS_COUNT' => 3,
        '>NEW_ELEMENTS_COUNT' => 5,
    ])
    //группируем выборку по ID инфоблока
    ->setGroup('ID');

Пример 4. SELECT с подзапросом.

Запрос с подзапросом.

Получим количество активных элементов у инфоблоков. Для связи с родительским запросом используем Bitrix\Main\DB\SqlExpression.

//формируем подзапрос - выберем только активные элементы
$subQuery = new \Bitrix\Main\Entity\Query(Bitrix\Iblock\ElementTable::getEntity());
$subQuery
    ->registerRuntimeField('CNT', [
        'data_type' => 'integer',
        'expression' => ['COUNT(*)']
    ])
    ->setSelect([
        'CNT'
    ])
    ->setFilter([
        'ACTIVE' => 'Y',
        'IBLOCK_ID' => new Bitrix\Main\DB\SqlExpression('%s')  //сюда позже подставим алиас поля содержащий ID инфоблока из родительского запроса
    ]);
//получаем SQL подзапроса
$subQuerySql = $subQuery->getQuery();

//формируем запрос
$query = new \Bitrix\Main\Entity\Query(Bitrix\Iblock\IblockTable::getEntity());
$query
    ->registerRuntimeField('ACTIVE_ELEMENTS_CNT', [
        'expression' => ['(' . $subQuerySql . ')', 'ID'] //здесь как раз и связываем родительский запрос с подзапросом по ID инфоблока
        //не забываем обернуть в скобки SQL подзапроса, иначе запрос будет некорректным
    ])
    ->setSelect([
        'ID',
        'ACTIVE_ELEMENTS_CNT',
    ]);

Пример 5. WHERE с подзапросом.

Выберем инфоблоки с 10 активными элементами

//формируем подзапрос
$subQuery = new \Bitrix\Main\Entity\Query(Bitrix\Iblock\ElementTable::getEntity());
$subQuery
    ->registerRuntimeField('CNT', [
        'data_type' => 'integer',
        'expression' => ['COUNT(*)']
    ])
    ->setSelect([
        'CNT'
    ])
    ->setFilter([
        'ACTIVE' => 'Y',
        'IBLOCK_ID' => new Bitrix\Main\DB\SqlExpression('%s')
    ]);
$subQuerySql = $subQuery->getQuery();

//формируем запрос
$query = new \Bitrix\Main\Entity\Query(Bitrix\Iblock\IblockTable::getEntity());
$query
    ->registerRuntimeField('ACTIVE_ELEMENTS_CNT', [
        'expression' => ['(' . $subQuerySql . ')', 'ID']
    ])
    ->setSelect([
        'ID',
    ])
    ->setFilter([
        '=ACTIVE_ELEMENTS_CNT' => 10,
    ]);

bitrix-orm.examples's People

Contributors

coldshine avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.