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个查询,有没有办法将其缩放?

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

即,$this->likes->count()而不是likes()->count()

以及类似的东西,以检查用户是否喜欢,而不是通过查询。

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

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

最新更新