查找已标记为X和Y但未标记为Z的文章

时间:2019-07-19 07:38:37

标签: php cakephp cakephp-3.0

比方说,我的文章可以包含许多标签。我希望能够找到所有标记为X和Y,但未标记为Z的文章。

数据库看起来像这样:

文章

  • id
  • 标题
  • 身体

标签

  • id
  • 名称

articles_tags

  • article_id
  • tag_id

现在,如果我想查找所有被标记为X和Y的文章,则可以这样做:

$tags = ['X', 'Y'];
$articles = TableRegistry::get('Articles');
$articles = $articles
    ->find()
    ->innerJoinWith('Tags')
    ->where(['Tags.name IN' => $tags])
    ->group(['Articles.id'])
    ->having([$this->query()->newExpr('COUNT(DISTINCT Tags.name) = ' . count($tags))]);

或者,如果我想查找所有未标记为Z的文章,可以这样做:

// ...
$articles = $articles
    ->find()
    ->notMatching('Tags', function ($q) use ($tags) {
        return $q->where(['Tags.name IN' => $tags]);
    });

但是,如果我想查找所有标记为X和Y而不是Z的文章怎么办?我已经花了数小时试图获得有效的查询,但是我无法弄清楚。

如果将这两个查询结合在一起,则会出现以下错误:

Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Tags.name' in 'where clause'

组合查询如下:

$tags = ['X', 'Y'];
$tags_not = ['Z'];
$articles = TableRegistry::get('Articles');
$articles = $articles
    ->find()
    ->innerJoinWith('Tags')
    ->where(['Tags.name IN' => $tags])
    ->group(['Articles.id'])
    ->having([$this->query()->newExpr('COUNT(DISTINCT Tags.name) = ' . count($tags))])
    ->notMatching('Tags', function ($q) use ($tags_not) {
        return $q->where(['Tags.name IN' => $tags_not]);
    });

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

$excluded = $this->Articles
    ->find()
    ->select('id')
    ->matching('Tags', function($q) use($tags_not) {
        return $q->where(['Tags.name IN' => $tags_not]);
})->toArray();
$excludedIds = array_column($excluded, 'id');

$articles = $this->Articles
    ->find()
    ->where(['Articles.id NOT IN' => $excludedIds])
    ->matching('Tags', function($q) use($tags) {
        return $q->where(['Tags.name IN' => $tags]);
});