Задать вопрос
dikey58
@dikey58
Самоучка - web-разработчик

Как объединить результаты getList, в котором объединяются две таблицы?

Пытаюсь сформировать запрос, чтобы было одним запросом к БД.
\Bitrix\Sale\Internals\UserPropsTable::getList([
            "select" => ["*", "PROFILE_" => "PROFILE.*"],
            "filter" => ["PERSON_TYPE_ID" => 49163, "ID" => 12,
            "runtime" => [
                new \Bitrix\Main\Entity\ReferenceField(
                    'PROFILE',
                    \Bitrix\Sale\Internals\UserPropsValueTable::class,
                    array('=this.ID' => 'ref.USER_PROPS_ID')
                ),
            ]
        ])->fetchAll();

Но результат разбивается на несколько элементов массива.
[
        {
            "ID": "12",
            "NAME": "Проверка заголовка профиля",
            "USER_ID": "49163",
            "PERSON_TYPE_ID": "1",
            "DATE_UPDATE": {},
            "XML_ID": null,
            "VERSION_1C": null,
            "PROFILE_ID": "51",
            "PROFILE_USER_PROPS_ID": "12",
            "PROFILE_ORDER_PROPS_ID": "2",
            "PROFILE_NAME": "ФИО",
            "PROFILE_VALUE": "Проверка Работ Профиля"
        },
        {
            "ID": "12",
            "NAME": "Проверка заголовка профиля",
            "USER_ID": "49163",
            "PERSON_TYPE_ID": "1",
            "DATE_UPDATE": {},
            "XML_ID": null,
            "VERSION_1C": null,
            "PROFILE_ID": "52",
            "PROFILE_USER_PROPS_ID": "12",
            "PROFILE_ORDER_PROPS_ID": "3",
            "PROFILE_NAME": "E-mail",
            "PROFILE_VALUE": "test2@example.com"
        },
        {
            "ID": "12",
            "NAME": "Проверка заголовка профиля",
            "USER_ID": "49163",
            "PERSON_TYPE_ID": "1",
            "DATE_UPDATE": {},
            "XML_ID": null,
            "VERSION_1C": null,
            "PROFILE_ID": "53",
            "PROFILE_USER_PROPS_ID": "12",
            "PROFILE_ORDER_PROPS_ID": "4",
            "PROFILE_NAME": "Телефон",
            "PROFILE_VALUE": "+79370000000"
        }
    ]

Как сделать, чтобы результат был, не прибегая к циклам:
[
    {
        "ID": "12",
        "NAME": "Проверка заголовка профиля",
        "USER_ID": "49163",
        "PERSON_TYPE_ID": "1",
        "DATE_UPDATE": {},
        "XML_ID": null,
        "VERSION_1C": null,
        "PROFILE_DATA": [
            {
                "PROFILE_ID": "51",
                "PROFILE_USER_PROPS_ID": "12",
                "PROFILE_ORDER_PROPS_ID": "2",
                "PROFILE_NAME": "ФИО",
                "PROFILE_VALUE": "Проверка Работ Профиля"
            },
            {
                "PROFILE_ID": "52",
                "PROFILE_USER_PROPS_ID": "12",
                "PROFILE_ORDER_PROPS_ID": "3",
                "PROFILE_NAME": "E-mail",
                "PROFILE_VALUE": "test2@example.com"
            },
            {
                "PROFILE_ID": "53",
                "PROFILE_USER_PROPS_ID": "12",
                "PROFILE_ORDER_PROPS_ID": "4",
                "PROFILE_NAME": "Телефон",
                "PROFILE_VALUE": "+79370000000"
            }
        ]
    }
]

Результаты представлены в json формате.
  • Вопрос задан
  • 200 просмотров
Подписаться 1 Средний 4 комментария
Помогут разобраться в теме Все курсы
  • Нетология
    1C-программист: расширенный курс
    18 месяцев
    Далее
  • Яндекс Практикум
    Вайбкодинг
    2 месяца
    Далее
  • Академия Эдюсон
    Python-разработчик + ИИ
    9 месяцев
    Далее
Пригласить эксперта
Ответы на вопрос 2
Конечно у вас будут выводится данные в том виде, как вы указали в первом примере, потому-что join происходит по id пользователя, а каждое свойство пользователя хранится отдельной записью. Я бы на вашем месте получил бы данные пользователя, а потом по его id отдельным запросом его свойства и сгруппировал бы в цикле в том виде, как вам надо во втором примере.
Ответ написан
@Cyber-Pavel
Проблема, с которой вы столкнулись, не в том, что ваш getList работает неправильно. Дело в том, как ORM Bitrix формирует SQL JOIN: при соединении одной таблицы с другой через ReferenceField каждая связанная запись из второй таблицы создаёт отдельную строку. Поэтому вы видите повторение основного профиля для каждой записи из UserPropsValueTable.

К сожалению, чистого способа в getList получить массив, где вложенные данные объединены в один подмассив без циклов на PHP, нет. Bitrix ORM не умеет делать «группировку по родительской записи» на уровне fetch.

То, что вы хотите — это фактически структура JSON с вложенным массивом, и её формирование всегда происходит на стороне PHP после выборки.

Вот как можно сделать максимально компактно, без длинных циклов, используя array_reduce или foreach в одну строку:

$rows = \Bitrix\Sale\Internals\UserPropsTable::getList([
    "select" => ["*", "PROFILE_" => "PROFILE.*"],
    "filter" => ["PERSON_TYPE_ID" => 49163, "ID" => 12],
    "runtime" => [
        new \Bitrix\Main\Entity\ReferenceField(
            'PROFILE',
            \Bitrix\Sale\Internals\UserPropsValueTable::class,
            ['=this.ID' => 'ref.USER_PROPS_ID']
        ),
    ]
])->fetchAll();

$result = [];
foreach ($rows as $row) {
    $id = $row['ID'];
    if (!isset($result[$id])) {
        $result[$id] = $row;
        $result[$id]['PROFILE_DATA'] = [];
        // удаляем вложенные поля, которые пойдут в PROFILE_DATA
        unset(
            $result[$id]['PROFILE_ID'],
            $result[$id]['PROFILE_USER_PROPS_ID'],
            $result[$id]['PROFILE_ORDER_PROPS_ID'],
            $result[$id]['PROFILE_NAME'],
            $result[$id]['PROFILE_VALUE']
        );
    }
    $result[$id]['PROFILE_DATA'][] = [
        'PROFILE_ID' => $row['PROFILE_ID'],
        'PROFILE_USER_PROPS_ID' => $row['PROFILE_USER_PROPS_ID'],
        'PROFILE_ORDER_PROPS_ID' => $row['PROFILE_ORDER_PROPS_ID'],
        'PROFILE_NAME' => $row['PROFILE_NAME'],
        'PROFILE_VALUE' => $row['PROFILE_VALUE'],
    ];
}


// Превращаем в обычный массив без ключей ID
$result = array_values($result);
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы