【问题标题】:CakePHP 3.x: query for related postsCakePHP 3.x:查询相关帖子
【发布时间】:2015-11-26 15:00:57
【问题描述】:

我有 PostsTags 模型,与“属于多个”关联。

所以在我的数据库中,我有 poststags 表和一个带有 post_idtag_id 字段的 posts_tags 表。 tags 表有 post_count 字段,显示属于该标签的帖子数。

当我收到一个帖子时,我也会得到与之相关的标签。

$this->Posts->find()
    ->contain(['Tags'])
    ->where(['Posts.id' => $id])
    ->first());

现在,对于每个标签,我想获得一个具有该标签的帖子,不包括初始帖子,排序创建日期(created 字段)。 重要的是,每个标签都会获得一个帖子,而不是已经获得的帖子。

我可以使用foreach 并为每个标签获取一个包含它的帖子,方法是排除初始帖子的 ID 和已经获得的 ID。

我想知道我是否可以用一个查询来做到这一点,并有一个可以使用的示例。

谢谢。


编辑
临时解决方案,对每个标签使用查询

首先,我得到主帖:

$post = $this->Posts->find()
    ->contain(['Tags'])
    ->where(['Posts.id' => $id])
    ->first();

在这种情况下,帖子是通过其 ID 恢复的,但您可以采取不同的做法。您也可以使用缓存。
重要的事情$post 变量。

现在(使用缓存是个好主意……):

//Tries to gets related posts from cache
$related = Cache::read($cache = sprintf('related_posts_for_%s', $post->id), 'posts');

if(empty($related)) {
    $tags = $post->tags;

    //Re-orders tags, using the "post_count" field, then based on the popularity of tags
    usort($tags, function($a, $b) { return $b['post_count'] - $a['post_count']; });

    //Gets only the first 5 tags
    $tags = array_slice($tags, 0 , 5);

    //This array will be contain the ID to be excluded
    $exclude = [$post->id];

    //Gets a related post for each tag
    //Reveres the tags order, because the tags less popular have less chance to find a related post
    foreach(array_reverse($tags) as $tag) {
        $post = $this->Posts->find('active')
            ->select(['id', 'title', 'slug'])
            ->matching('Tags', function($q) use($tag) {
                return $q->where(['Tags.id' => $tag->id]);
            })
            ->where(['Posts.id NOT IN' => $exclude])
            ->first();

        //Adds the post to the related posts and its ID to the IDs to be excluded for the next query
        if(!empty($post)) {
            $related[] = $post;
            $exclude[] = $post->id;
        }
    }

    Cache::write($cache, $related, 'posts');
}

//Related posts
debug($related);

注意:在此代码之后,$post 变量不再包含原始帖子。注意相关帖子或使用不同的变量名称。

【问题讨论】:

    标签: cakephp cakephp-3.0


    【解决方案1】:

    试试这个(未测试)

    $this->Posts->find()
    ->contain([
        'Tags',
        'Tags.Posts' => function($q) use($id) {
            $q->where(['id !=' => $id])
                ->order(['created' => 'desc'])
                ->limit(1);
            return $q;
         }
       ])
    ->where(['Posts.id' => $id])
    ->first());
    

    但是通过这种方式,您可能会收到两次帖子(我现在看到您不想要这个)

    【讨论】:

    • 感谢@arilia。但我想将这两个查询分开。我想这是同一件事,但使用matching()。这样对吗?但是在这种情况下有一个问题:这段代码可能需要两次相同的帖子?
    • 我不明白:你在 OP 中说你只想要一个查询,现在你想要两个。
    • 假设我的帖子有ab 标签。另一个帖子具有相同的标签。对于每个标签,同一篇文章(第二篇)将被获取两次?
    • 我正在尝试您的代码。 limit()似乎有问题,它总是只得到一个记录
    • 它应该为每个标签获得一个帖子。不是原始帖子的最新帖子(或者更可能是最旧的帖子,我猜,只要我由 created asc 排序)。是的:如果一个帖子有 a 和 b 标签,你会得到两次,除非有另一个旧的帖子有 b 标签
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-19
    • 1970-01-01
    • 2015-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多