Cakephp 如何限制每个记录/组包含的关联?

Cakephp 如何限制每个记录/组包含的关联?,cakephp,orm,associations,cakephp-3.0,query-builder,greatest-n-per-group,Cakephp,Orm,Associations,Cakephp 3.0,Query Builder,Greatest N Per Group,我有一个模型,文章,有很多摘要。我想载入10篇最新的文章,每一篇文章的摘要都有最高的分数。我的函数如下所示: public function getArticles($category, $viewName) { $subArticles = $this->Articles->findByCategory($category)->contain([ 'Abstracts' => function ($q) {

我有一个模型,文章,有很多摘要。我想载入10篇最新的文章,每一篇文章的摘要都有最高的分数。我的函数如下所示:

public function getArticles($category, $viewName) {
            $subArticles = $this->Articles->findByCategory($category)->contain([
                    'Abstracts' => function ($q) {
                            return $q
                                    ->select(['body', 'points', 'article_id'])
                                    ->where(['Abstracts.approved' => true])
                                    ->limit(10)
                                    ->order(['Abstracts.points' => 'DESC']);
                    }
            ])
            ->limit(10)
            ->order(['Articles.created' => 'DESC']) ;
            $this->set( $viewName . 'Articles', $subArticles );
    }
我得到的结果不是我想要的。查看SQL,首先CakePHP获取类别中所有内容的articles.id(很好)。然后,CakePHP进入Abstracts表,使用刚刚找到的10篇文章。id,并要求获得投票率最高的10篇摘要(属于这些文章)

问题是,我希望每篇文章都有一个摘要,而不是属于该类别任何文章的10个摘要。我怎样才能解决这个问题?谢谢

编辑

ndm建议这是一个副本,所以我尝试在那里的解决方案。也就是说,我在模型中添加了以下内容:

 $this->hasOne('TopAbstract', [
            'className' => 'Abstracts',
            'foreignKey' => 'abstract_id',
            'strategy' => 'select',
            'sort' => ['TopAbstract.points' => 'DESC'],
            'conditions' => function ($e, $query) {
            $query->limit(1);
            return $e;
    } ]);
然后我尝试按类别查找包含(['TopAbstract'])的文章,只有这样才能终止我的SQL。它死得很惨:

Error: SQLSTATE[HY000]: General error: 1 near ")": syntax error
Debug甚至没有显示杀死它的查询,所以我不知道如何调试这个查询

编辑


有点自言自语,但错误肯定在hasOne的“条件”部分。我把它拿出来,效果很好。在互联网上找不到这样的例子。。有人知道吗?

您正在寻找的是问题的解决方案。您没有提到任何特定的RDBMS,但请参见

图书馆解决方案 对于那些有点冒险精神的人,我开发了一些自定义关联,这些关联透明地集成到ORM层中,并允许对
有许多
以下关系的每个组进行基本限制:

使用它们,问题的解决方案将是建立一个这样的协会:

public function getArticles($category, $viewName) {
            $subArticles = $this->Articles->findByCategory($category)->contain([
                    'Abstracts' => function ($q) {
                            return $q
                                    ->select(['body', 'points', 'article_id'])
                                    ->where(['Abstracts.approved' => true])
                                    ->limit(10)
                                    ->order(['Abstracts.points' => 'DESC']);
                    }
            ])
            ->limit(10)
            ->order(['Articles.created' => 'DESC']) ;
            $this->set( $viewName . 'Articles', $subArticles );
    }
$this
->partitionableHasMany('TopAbstracts'))
->setClassName('Abstracts')
->设定限制(1)
->塞斯特([
'Abstracts.points'=>'DESC',
'Abstracts.id'=>'ASC',
]);
TopAbstracts
可以像任何其他关联一样被包含

关联级别上的自定义解决方案

让我们试一试,这里有三种可以应用于关联级别的选项(定义条件也可以移入自定义查找器),但是您可能认为它们不是“简单的”。


选择策略-在分组上使用联接,最大值子查询
$this->hasOne('TopAbstracts'[
'className'=>'Abstracts',
“策略”=>“选择”,
“条件”=>函数(\Cake\Database\Expression\QueryExpression$exp、\Cake\ORM\Query$Query){
$query->innerJoin(
[
“AbstractsFilter”=>$query
->连接()
->newQuery()
->选择(['article_id','points'=>$query->func()->max('points'))
->来自(‘摘要’)
->组(‘物品编号’)
],
[
'TopAbstracts.article\u id=AbstractsFilter.article\u id',
'TopAbstracts.points=AbstractsFilter.points'
]
);
返回[];
}
]);
这将通过一个基于最大点的连接查询来选择顶级摘要,它看起来像

选择
TopAbstracts.id作为'TopAbstracts\uuu id'。。。
从…起
摘要
内连接(
挑选
文章编号(最大(分))为`分`
从…起
摘要
分组
第11条
)
抽象过滤器(
TopAbstracts.article\u id=AbstractsFilter.article\u id
及
TopAbstracts.points=AbstractsFilter.points
)
哪里
(1,2,3,4,5,6,7,8,…)中的TopAbstracts.article_id

选择策略-使用左自联接筛选
$this->hasOne('TopAbstracts'[
'className'=>'Abstracts',
“策略”=>“选择”,
“条件”=>函数(\Cake\Database\Expression\QueryExpression$exp、\Cake\ORM\Query$Query){
$query->leftJoin(
['AbstractsFilter'=>'abstracts'],
[
'TopAbstracts.article\u id=AbstractsFilter.article\u id',
'TopAbstracts.pointsadd(['AbstractsFilter.id为NULL']);
}
]);
这将使用一个自联接,该自联接根据没有
a.points
的行进行筛选,它将类似于

选择
TopAbstracts.id作为'TopAbstracts\uuu id'。。。
从…起
摘要
左连接
抽象过滤(
TopAbstracts.article\u id=AbstractsFilter.article\u id
及
TopAbstracts.points

联接策略-使用联接条件的子查询
$this->hasOne('TopAbstracts'[
'className'=>'Abstracts',
“foreignKey”=>错误,
“条件”=>函数(\Cake\Database\Expression\QueryExpression$exp、\Cake\ORM\Query$Query){
$subquery=$query
->连接()
->newQuery()
->选择(['SubTopAbstracts.id'])
->from(['SubTopAbstracts'=>'abstracts']))
->其中(['Articles.id=SubTopAbstracts.article\u id']))
->顺序(['SubTopAbstracts.points'=>'DESC'])
->限额(1);
返回$exp->add(['TopAbstracts.id'=>$subquery]);
}
]);
这将使用一个相关的子查询,该子查询使用一个非常特定的select,并通过简单的排序和限制来选择最上面的注释。请注意,
foreignKey
选项被设置为
false
,以避免额外的
Articles.id=TopAbstracts.article\u id
条件被编译到联接条件中