Могу ли я отсортировать дочерние элементы, отличные от родительских, в многопоточном запросе CakePHP 3?

У меня есть вопросы по поводу комментариев. Можно ли заказать комментарии DESC и дочерние комментарии ASC в этом запросе (или на уровне таблицы) или мне следует выполнить модификацию после запроса?

Ниже вы можете найти мой запрос, который заказывает все в DESC.

`` `

$comments = $this->Comments
            ->find('threaded', ['order' => ['Comments.created' => 'DESC']])
            ->contain(['Users'])
            ->matching(
                'BoardItems',
                function ($q) use ($boardItemId) {
                    return $q->where(
                        [
                            'BoardItems.id' => $boardItemId
                        ]
                    );
                }
            )
            ->all();

`` `

1 ответ

Решение

На уровне SQL

Вы должны быть в состоянии применить решение, предложенное в MySql: ORDER BY parent and child, которое

  1. использования COALESCE сначала сгруппировать / отсортировать родителей
  2. группирует детей путем тестирования наNULL ID родителя
  3. сортирует сгруппированных детей

В вашем случае вы бы сортировать по created вместо idто есть что-то вроде

ORDER BY 
    COALESCE(Comments.parent_id, Comments.created) DESC, 
    Comments.parent_id IS NOT NULL, 
    Comments.created ASC

Чтобы построить это в правильном стиле построения запросов, вам нужно использовать order() а также orderDesc() методы, так что вы можете использовать выражения запроса, что-то вроде

$query = $this->Comments
    ->find('threaded');

$comments = $query
    // ->contain(...)
    // ->matching(...)

    // COALESCE(Comments.parent_id, Comments.created) DESC
    ->orderDesc($query->func()->coalesce([
        'Comments.parent_id' => 'identifier',
        'Comments.created' => 'identifier'
    ]))

    // Comments.parent_id IS NOT NULL
    ->order($query->newExpr()->isNotNull('Comments.parent_id'))

    // Comments.created ASC
    ->order(['Comments.created' => 'ASC'])

    ->all();

Смотрите также

На уровне PHP

Последующая сортировка также будет возможна, например, с использованием рекурсивного средства форматирования результатов:

$sortChildren = function($row) use (&$sortChildren) {
    if (!empty($row['children'])) {
        $row['children'] =
            collection($row['children'])
                ->sortBy('created', SORT_ASC)
                ->map($sortChildren)
                ->toArray();
    }
    return $row;
};

$comments = $this->Comments
    ->find('threaded')
    // ->contain(...)
    // ->matching(...)
    ->order(['Comments.created' => 'DESC'])
    ->formatResults(function ($results) use ($sortChildren) {
        return $results->map($sortChildren);
    })
    ->all();

Это будет получать все сортировать по убыванию, а затем сортировать все children массивы по возрастанию created поле. Точно так же вы можете сортировать вещи перед тем, как выводить / использовать их в своих представлениях, в зависимости от того, что именно вы планируете делать с результатами.

Если вы хотите сохранить все в таблице, вы можете, например, обернуть все это в пользовательском искателе и / или получить закрытие сортировки с помощью метода вашего класса таблицы.

Смотрите также

Другие вопросы по тегам