【问题标题】:Can I sort children different than parent in CakePHP 3 threaded query?我可以在 CakePHP 3 线程查询中对不同于父级的子级进行排序吗?
【发布时间】:2016-08-13 08:36:21
【问题描述】:

我有一个关于线程化 cmets 的问题。是否可以从此查询(或表级别)订购 cmets DESC 和子 cmets 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();

```

【问题讨论】:

    标签: cakephp tree cakephp-3.0 cakephp-3.x


    【解决方案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();
    

    这将检索降序排序的所有内容,然后按created 字段对所有children 数组进行升序排序。同样,您可以在输出/在视图中使用它们之前对它们进行排序,具体取决于您计划对结果做什么。

    如果您想将内容保存在表格中,例如,您可以将其全部包装在自定义查找器中和/或通过表格类上的方法检索排序闭包。

    另见

    【讨论】:

    • 感谢您的详细回答,我可以在星期一尝试,但从外观上看,两者都可以解决我的问题。我正在考虑使用类似于第二个的东西,使用集合,但 mysql 解决方案似乎更好。
    • 现在终于尝试了mysql解决方案,效果很好,再次感谢
    猜你喜欢
    • 2013-07-23
    • 2021-10-20
    • 2013-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-24
    • 2010-11-19
    • 2018-07-31
    相关资源
    最近更新 更多