Cakephp 如何限制每个记录/组包含的关联?
我有一个模型,文章,有很多摘要。我想载入10篇最新的文章,每一篇文章的摘要都有最高的分数。我的函数如下所示: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) {
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
条件被编译到联接条件中