Laravel:处理多个计数查询

时间:2019-08-01 13:34:27

标签: php laravel

在我的应用程序中,我有3个模型UserAnnouncementLike。用户可以通过以下关系喜欢公告。

公告模型

/**
 * Get the users that have liked this article
 *
 * @return void
 */
public function likes()
{
    return $this->morphToMany(User::class, 'likeable');
}

类似模型

/**
 * Get all of the announcements that are assigned this like.
 */
public function announcements()
{
    return $this->morphedByMany(Announcement::class, 'likeable');
}

LikeController中使用几种方法来处理录制点赞。

/**
 * Handle the liking of an announcements by passing in the class and ID of the model instance
 *
 * @param int $id
 * @return void
 */
public function likeAnnouncement($id)
{
    // here you can check if product exists or is valid or whatever
    $this->handleLike(Announcement::class, $id);

    return redirect()->back();
}

/**
 * Handle a Like
 * First we check the existing Likes as well as the currently soft deleted likes.
 * If this Like doesn't exist, we create it using the given fields
 *
 * @param [type] $type
 * @param [type] $id
 * @return void
 */
public function handleLike($type, $id)
{
    $existing_like = Like::whereLikeableType($type)
        ->whereLikeableId($id)
        ->whereUserId(Auth::user()->id)
        ->first();

    if (is_null($existing_like)) {
        // This user hasn't liked this thing so we add it
        Like::create([
            'user_id' => Auth::user()->id,
            'likeable_id'   => $id,
            'likeable_type' => $type,
        ]);
    } else {
        // As existingLike was not null we need to effectively un-like this thing
        $existing_like->delete();
    }
}

在索引刀片中,我显示公告以及喜欢"this announcement was liked by you and 12 others"这样的语句的人

@foreach($announcements as $key => $announcement)
    <div class="announcements__item">
        <p class="mb-0"><a class="announcements__item-header d-block" href="#" data-toggle="modal" data-target="#announcement{{$key}}">{{ $announcement->message }}</a></p>
        <small class="announcements__item-meta d-block">Posted {{$announcement->published_at->diffForHumans()}} | 
            <span class="highlight-pink">{{ $announcement->user->full_name }}</span> | 
            <a title="{{$announcement->user_has_liked ? "Unlike this announcement" : "Like this announcement"}}" class="ml-2 announcements__item-like-btn @if($announcement->user_has_liked) liked @endif" href="" data-id="{{$announcement->id}}"><i class="fas fa-thumbs-up"></i></a> 
            <span class="ml-1" style="display: none;">Updating...</span>
        </small>

        {{-- If this is only liked by the current user --}}
        @if($announcement->likes_count === 1 && $announcement->user_has_liked)
            <small class="mb-0 announcements__item-like-text d-block">You liked this.</small>
        @endif
        {{-- If this is liked by 1 other user and not the current user --}}
        @if($announcement->likes_count_excluding_auth_user === 1 && !$announcement->user_has_liked)
            <small class="mb-0 announcements__item-like-text d-block">{{$announcement->random_user_who_liked_this->full_name}} liked this.</small>
        @endif
        {{-- If this is liked by other users and NOT the current user --}}
        @if($announcement->likes_count > 1 && !$announcement->user_has_liked)
            <small class="mb-0 announcements__item-like-text d-block">{{$announcement->random_user_who_liked_this->full_name}} and <span id="announcement_{{$announcement->id}}" data-likes="{{$announcement->likes_count_excluding_auth_user}}" class="announcements__item-likes">{{$announcement->likes_count_excluding_auth_user}}</span> other colleagues liked this.</small>
        @endif
        {{-- If this is liked by 1 other user and the current user --}}
        @if($announcement->likes_count_excluding_auth_user === 1 && $announcement->user_has_liked)
            <small class="mb-0 announcements__item-like-text d-block">You and {{$announcement->random_user_who_liked_this->full_name}} liked this.</small>
        @endif
        {{-- If this is liked by other users and the current user --}}
        @if($announcement->likes_count_excluding_auth_user > 1 && $announcement->user_has_liked)
            <small class="mb-0 announcements__item-like-text d-block">You, {{$announcement->random_user_who_liked_this->full_name}} and <span id="announcement_{{$announcement->id}}" data-likes="{{$announcement->likes_count_excluding_auth_user}}" class="announcements__item-likes">{{$announcement->likes_count_excluding_auth_user}}</span> other colleagues liked this.</small>
        @endif
    </div>
@endforeach

Announcement模型中,我有各种访问器:

/**
 * Get the users that have liked this article
 *
 * @return void
 */
public function likes()
{
    return $this->morphToMany(User::class, 'likeable');
}

/**
 * Check if the user has liked this announcement
 *
 * @return void
 */
public function getUserHasLikedAttribute()
{
    $like = $this->likes()->whereUserId(auth()->user()->id)->first();

    return (!is_null($like)) ? true : false;
}

/**
 * Get the users that have liked this article
 *
 * @return void
 */
public function getLikesCountAttribute()
{
    return $this->likes()->count();
}

/**
 * Get count of users who liked the announcement excluding the logged in user
 *
 * @return void
 */
public function getLikesCountExcludingAuthUserAttribute()
{
    return $this->likes()->where('username', '<>', auth()->user()->username)->count();
}

/**
 * Get random user who liked this announcement
 *
 * @return void
 */
public function getRandomUserWhoLikedThisAttribute()
{
    return $this->likes()->where('username', '<>', auth()->user()->username)->inRandomOrder()->first();
}

/**
 * Get all users who liked this announcement
 *
 * @return void
 */
public function getUsersWhoLikedThisAttribute()
{
    return $this->likes()->where('username', '<>', auth()->user()->username)->get();
}

这些访问者将执行以下操作:

  • 获得喜欢的次数
  • 检查当前用户是否喜欢该公告
  • 获得随机用户就像是公告
  • 获取所有喜欢该公告的用户,但不包括已验证的用户

我要实现什么目标?

根据不同的情况,我想显示以下内容:

  • 你喜欢这个
  • 您,史密斯先生和其他12个人都这样
  • 史密斯先生和其他12个人这样

我提供的内容在一定程度上是行得通的,但是,由于此段运行了100多个查询,因此在任何地方都可以使用计数,有没有办法我可以缩小规模?

1 个答案:

答案 0 :(得分:0)

您的likes关系是否热切?如果是这样(甚至可能不是这样),您可以用急切加载的集合的计数/过滤替换其他查询。

$this->likes->count()而非likes()->count()

与此类似的事情是检查用户是否喜欢,而不是通过查询来检查。

public function getUserHasLikedAttribute()
{
    return ! $this->likes
        ->filter(function ($like) {
            return $like->user_id === auth()->user()->id;    
        })
        ->isEmpty();
}

显然,如果您期望非常大的数据集,那么这可能是个问题,但这是另一种选择。