Блог Горошко Андрея 1C-Битрикс Фильтрация по множественным свойствам в Битрикс: Логика «И» и «ИЛИ»

Фильтрация по множественным свойствам в Битрикс: Логика «И» и «ИЛИ»

Средний рейтинг
Еще нет оценок

При фильтрации по множественным свойствам возникает важный вопрос: как именно должны работать условия?

  • Логика «ИЛИ» (OR): Найти элементы, у которых свойство имеет хотя бы одно из указанных значений.
  • Логика «И» (AND): Найти элементы, у которых свойство имеет все указанные значения одновременно.

Логика «ИЛИ» — простой случай

Это поведение по умолчанию как в старом API, так и в D7 ORM. Достаточно передать массив значений в фильтр.

Пример (старое API CIBlockElement::GetList):
Найти товары, у которых цвет «Красный» ИЛИ «Синий».

$arFilter = [
    "IBLOCK_ID" => 10,
    "ACTIVE" => "Y",
    "PROPERTY_COLOR" => ["Красный", "Синий"] // Просто передаем массив
];
$rsElements = CIBlockElement::GetList([], $arFilter);

// Пример (D7 ORM `ElementTable::getList`):

$result = ElementTable::getList([
    'filter' => [
        '=IBLOCK_ID' => 10,
        '=ACTIVE' => 'Y',
        '=PROPERTY_COLOR.VALUE' => ["Красный", "Синий"] // Тоже просто массив
    ]
]);

Логика «И» — сложный случай

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

Задача: Найти товары, у которых цвет и «Красный», и «Синий» одновременно.

Решение для старого API (CIBlockElement::GetList)

Нужно создать вложенный фильтр, который будет проверять наличие каждого значения отдельно и считать совпадения.

$colors = ["Красный", "Синий"];
$colorsCount = count($colors);

$arFilter = [
    "IBLOCK_ID" => 10,
    "ACTIVE" => "Y",
    // Создаем подфильтр
    [
        "LOGIC" => "AND",
        "ID" => CIBlockElement::SubQuery("ID", [
            "IBLOCK_ID" => 10,
            "PROPERTY_COLOR" => $colors, // Находим все элементы, у которых есть хотя бы один из цветов
            "CNT" => $colorsCount // Группируем по ID и считаем кол-во совпадений
        ]),
    ],
];

// Указываем группировку для SubQuery
$arGroupBy = ["ID"]; 

$rsElements = CIBlockElement::GetList([], $arFilter, $arGroupBy);

Как это работает:

  1. CIBlockElement::SubQuery создает подзапрос.
  2. Внутри подзапроса мы ищем все элементы, у которых свойство COLOR равно либо «Красный», либо «Синий».
  3. Ключевой момент: мы группируем результат по ID элемента и добавляем CNT => $colorsCount (в нашем случае CNT => 2). Это означает, что в результат подзапроса попадут только те ID элементов, у которых нашлось ровно 2 совпадения по цветам.
  4. Основной запрос выбирает элементы, ID которых вернул подзапрос.

Решение для D7 ORM

В D7 ORM это делается элегантнее с помощью runtime-полей и подзапросов Query.

use Bitrix\Iblock\ElementTable;
use Bitrix\Main\Entity\Query;
use Bitrix\Main\Entity\ExpressionField;

$colors = ["Красный", "Синий"];
$colorsCount = count($colors);

// Создаем подзапрос
$subQuery = new Query(ElementTable::getEntity());
$subQuery
    ->setSelect(['IBLOCK_ELEMENT_ID'])
    ->where('IBLOCK_ID', 10)
    ->whereIn('PROPERTY_COLOR.VALUE', $colors)
    ->addGroup('IBLOCK_ELEMENT_ID')
    ->having('CNT', '=', $colorsCount)
    ->registerRuntimeField(
        new ExpressionField('CNT', 'COUNT(DISTINCT %s)', 'PROPERTY_COLOR.VALUE')
    );

// Основной запрос
$result = ElementTable::getList([
    'select' => ['ID', 'NAME'],
    'filter' => [
        '=IBLOCK_ID' => 10,
        '@ID' => $subQuery // Используем подзапрос
    ]
]);

Как это работает:
Логика та же, но выражена более явно:

  1. Мы создаем объект Query для подзапроса.
  2. Выбираем ID элементов, фильтруем по нужным цветам (whereIn).
  3. Группируем по IBLOCK_ELEMENT_ID.
  4. Добавляем runtime-поле CNT для подсчета уникальных совпавших цветов.
  5. Используем having (аналог WHERE для сгруппированных данных), чтобы оставить только те элементы, у которых CNT равен количеству искомых цветов.
  6. В основном запросе в filter мы используем оператор @ (аналог SQL IN), передавая ему наш готовый подзапрос.

Вывод:
Фильтрация по множественным свойствам с логикой «ИЛИ» проста и интуитивна. Для логики «И» требуется использовать более сложную конструкцию с подзапросом и группировкой.

D7 ORM, хотя и выглядит многословнее в этом случае, предоставляет более гибкий и читаемый синтаксис для построения таких сложных запросов по сравнению с «магическим» CNT в старом API.

множественное свойство, фильтр ‘И’, CIBlockElement::GetList, D7 ORM, подзапрос, фильтрация Битрикс, логика ‘И’, логика ‘ИЛИ’.

Мой рейтинг:

Добавить комментарий

Related Post

Создание комплексных компонентов в Битрикс: SEF_MODE, urlrewrite и ЧПУСоздание комплексных компонентов в Битрикс: SEF_MODE, urlrewrite и ЧПУ

Средний рейтинг Еще нет оценок Комплексный компонент не выводит информацию сам. Его главная задача — работать как маршрутизатор (роутер). Он анализирует URL-адрес и, в зависимости от него, подключает один из нескольких простых компонентов,

Локализация в Битрикс: Правильная работа с языковыми файлами (GetMessage и Loc::getMessage)Локализация в Битрикс: Правильная работа с языковыми файлами (GetMessage и Loc::getMessage)

Средний рейтинг Еще нет оценок Жестко «зашивать» текстовые строки (заголовки, названия кнопок, сообщения) прямо в код — плохая практика. Это затрудняет перевод сайта на другие языки и усложняет поддержку. В

Отправка почты в Битрикс: CEvent, Почтовые шаблоны и СобытияОтправка почты в Битрикс: CEvent, Почтовые шаблоны и События

Средний рейтинг 5 из 5 звезд. 1 голосов. Отправка email-уведомлений (о регистрации, новом заказе, сообщении из формы) — базовая потребность любого сайта. В Битрикс для этого реализована гибкая система, состоящая