CakePHP 3按关键字按页面分组查找

时间:2015-09-05 22:40:45

标签: php mysql cakephp

我当前的表格配置如下

PagesTable

$this->belongsToMany('Keywords', ['through' => 'PagesKeywords']);

PagesKeywordsTable

架构 id,page_id,keyword_id,相关性

$this->belongsTo('Pages');
$this->belongsTo('Keywords');

KeywordsTable

$this->belongsToMany('Pages', ['through' => 'PagesKeywords']);

现在是我正在努力的事情......

通过关键字查找网页,使用精确的数组然后按 PagesKeywords.relevance

排序

(这基本上是存储每页关键字重复的次数,因此连接表中没有重复的关键字)

我目前这个工作正常,除了它按关键字本身对关键字的结果进行分组,我需要将它们按Pages.id分组。

以下是我在Pages控制器中的搜索操作:

$keywords = explode(" ", $this->request->query['q']);

$query = $this->Pages->Keywords->find()
         ->where(['keyword IN' => $keywords])
          ->contain(['Pages' => [
            'queryBuilder' => function ($q) {
                return $q->order([
                       'PagesKeywords.relevance' =>'DESC'
                ])->group(['Pages.id']);
            }
        ]]);


 $pages = array();

 foreach($query as $result) {

            $pages[] = $result;

        }

我知道这似乎是一种落后的做事方式,但它是我似乎能够通过_joinTable订购的唯一方式(PagesKeywords.relevance)

这会返回我需要的结果,但现在需要按Pages.id进行分组,这就是整个事情进入底池的地方..

要明确我想要的结构是:

Page data 1
Page data 2
Page data 3
Page data 4

目前正在返回的位置:

Keyword "google"
------- Page data 1
------- Page data 2
------- Page data 3
------- Page data 4

Keyword "something"
------- Page data 1
------- Page data 2
------- Page data 3
------- Page data 4

如果你能帮助我那么棒!

由于

1 个答案:

答案 0 :(得分:0)

如果您在使用ORM进行复杂查询时遇到问题,我发现找出我需要的SQL所需的SQL总是更容易,然后将其调整到ORM。

您正在寻找的查询将是这样的(使用MySQL引擎...... MySQL Handles字段在GROUP BY子句中比其他SQL引擎更自由地选择)

SELECT Pages.*, COUNT(DISTINCT(PagesKeywords.keyword_id)) AS KeywordCount
FROM pages Pages
INNER JOIN pages_keywords PagesKeywords ON (PagesKeywords.page_id = Pages.id)
INNER JOIN keywords Keywords ON (Keywords.id = PagesKeywords.keyword_id)
WHERE Keywords.name IN ('keyword1','keyword2')
GROUP BY Pages.id

这将为您提供包含关键字的所有网页,KeywordCount将包含不同的附加关键字的数量。

所以这样的finder方法看起来像(在这里进行ad-hoc,所以我的语法可能会不稳定)

**在PagesTable模型中**

public function findPageKeywordRank(Query $q, array $options) {
  $q->select(['Pages.*','KeywordCount'=>$q->func()->count('DISTINCT(PagesKeywords.keyword_id)'])
  ->join([
    'PagesKeywords'=>[
     'table'=>'pages_keywords',
     'type'=>'inner',
     'conditions'=>['PagesKeywords.page_id = Pages.id']
    ],
    'Keywords'=>[
      'table'=>'keywords',
      'type'=>'inner',
      'conditions'=>['Keywords.id = PagesKeywords.keyword_id']
    ]
  ])
  ->group(['Pages.id']);
  return $q;
}

然后你可以查询所有查询器

$pages = TableRegistry::get("Pages")->find('PageKeywordRank')
                                    ->where(['Keywords.name'=>['keyword1','keyword2']]);