Блог Горошко Андрея 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, подзапрос, фильтрация Битрикс, логика ‘И’, логика ‘ИЛИ’.

Похожая задача в бизнесе?

Помогу автоматизировать процессы и внедрить ИИ

Меня зовут Андрей Горошко. Я Full-stack разработчик и эксперт по 1С-Битрикс. Настраиваю CRM Битрикс24, разрабатываю защищенные API и создаю умных ИИ-агентов для автоматизации рутины.

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

Related Post

Обновить поля головного товара catalog.product.sku.updateОбновить поля головного товара catalog.product.sku.update

Каждый PHP-разработчик, работающий с экосистемой Bitrix Framework, должен глубоко понимать работу её ключевых компонентов. В этой статье мы проведем подробный аудит темы «Обновить поля головного товара catalog.product.sku.update», проанализируем лучшие практики

Перевод сайта на 1С-Битрикс на микросервисную архитектуруПеревод сайта на 1С-Битрикс на микросервисную архитектуру

Профессиональная поддержка, модернизация и оптимизация производительности сайта на 1С-Битрикс — это гарантия высокой конверсии, стабильности продаж и защиты от киберугроз. Услуга «Перевод сайта на 1С-Битрикс на микросервисную архитектуру» включает вынос

result_modifier.php: Модификация данных компонента перед выводом в шаблонresult_modifier.php: Модификация данных компонента перед выводом в шаблон

Файл result_modifier.php — это специальный файл в шаблоне компонента, который выполняется после component.php, но до template.php. Его главная и единственная задача — модифицировать массив $arResult, подготавливая его к максимально простому выводу в шаблоне. Зачем он нужен? (Принцип