php - Laravel 多对多加载相关模型与计数

标签 php laravel-4 many-to-many eloquent pivot-table

我正在尝试链接 4 个表,并添加一个自定义字段,该字段通过使用 laravel 计算一些相关表的 ID 来计算。 我在 SQL 中有这个,它可以做我想做的事,但我认为它可以变得更有效率:

DB::select('SELECT 
                        posts.*,
                          users.id AS users_id, users.email,users.username,
                          GROUP_CONCAT(tags.tag ORDER BY posts_tags.id) AS tags,
                          COUNT(DISTINCT comments.id) AS NumComments, 
                          COUNT(DISTINCT vote.id) AS NumVotes
                        FROM 
                          posts    
                          LEFT JOIN comments ON comments.posts_id = posts.id
                          LEFT JOIN users ON users.id = posts.author_id
                          LEFT JOIN vote  ON vote.posts_id = posts.id
                          LEFT JOIN posts_tags  ON posts_tags.posts_id = posts.id
                          LEFT JOIN tags  ON tags.id = posts_tags.tags_id

                        GROUP BY 
                          posts.id, 
                          posts.post_title');

我试图通过这样做来使用 Eloquent 方式来实现它:

$trending=Posts::with(array('comments' => function($query)
                {
                    $query->select(DB::raw('COUNT(DISTINCT comments.id) AS NumComments'));

                },'user','vote','tags'))->get();

但是 NumComments 值未显示在查询结果中。 有什么线索可以解决吗?

最佳答案

你不能使用 with 来做到这一点,因为它执行单独的查询。

您需要的是简单的join。只需将您的查询翻译成类似的内容:

Posts::join('comments as c', 'posts.id', '=', 'c.id')
    ->selectRaw('posts.*, count(distinct c.id) as numComments')
    ->groupBy('posts.id', 'posts.post_title')
    ->with('user', 'vote', 'tags')
    ->get();

然后集合中的每个帖子都会有计数属性:

$post->numComments;

然而,您可以通过以下关系使其更容易:

虽然第一个解决方案在性能方面更好(除非你有大数据,否则可能不会引人注意)

// helper relation
public function commentsCount()
{
    return $this->hasOne('Comment')->selectRaw('posts_id, count(*) as aggregate')->groupBy('posts_id');
}

// accessor for convenience
public function getCommentsCountAttribute()
{
    // if relation not loaded already, let's load it now
    if ( ! array_key_exists('commentsCount', $this->relations)) $this->load('commentsCount');

    return $this->getRelation('commentsCount')->aggregate;
}

这将允许您这样做:

$posts = Posts::with('commentsCount', 'tags', ....)->get();
// then each post:
$post->commentsCount;

对于多对多关系:

public function tagsCount()
{
    return $this->belongsToMany('Tag')->selectRaw('count(tags.id) as aggregate')->groupBy('pivot_posts_id');
}

public function getTagsCountAttribute()
{
    if ( ! array_key_exists('tagsCount', $this->relations)) $this->load('tagsCount');

    $related = $this->getRelation('tagsCount')->first();

    return ($related) ? $related->aggregate : 0;
}

可以在此处找到更多此类示例 http://softonsofa.com/tweaking-eloquent-relations-how-to-get-hasmany-relation-count-efficiently/

关于php - Laravel 多对多加载相关模型与计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25662854/

相关文章:

php - 不区分大小写的排序数组

PHP:使用 WAMP 的内部服务器错误(启动时)

session - Paypal 重定向让我退出我的网站?

core-data - 多对多结构中的删除

mysql - MySQL 中的转换(多对多连接)表;允许重复条目将 1 列链接到不同表中的多个其他列

php - 是否可以从任何网站读取 PHP 中的 SSL 信息?

php - 如何在不使用 PHP 循环的情况下返回 MySQL 结果数组

php - Laravel4 - 处理整个应用程序和 mysql 之间的日期格式

php - Laravel - 上次登录日期和时间戳

list - Odoo 8 Many2many 验证和删除行