3 條 sql 是實現知乎評論,7 條 sql 實現點贊 + 評論,且可擴充套件

jcc123發表於2018-10-21

文章資料結構

Post
    - id
    - title
    - body
    - vote_count
    - comment_count

評論資料結構

Comment
    - id
    - title
    - body
    - commentable_id
    - commentable_type
    - parent_id
    - user_id
    - first_depth_id 一級評論id
    - vote_count
    - comment_count

點贊資料結構

    Vote
        - id
        - user_id
        - voteable_id
        - voteable_type

Post

public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable');
    }

    public function votes()
    {
        return $this->morphMany(Vote::class, 'voteable');
    }

Comment

 public function commentable()
    {
        return $this->morphTo();
    }

    public function parent()
    {
        return $this->belongsTo(Comment::class,'parent_id');
    }

    public function children()
    {
        return $this->hasMany(Comment::class, 'parent_id');
    }

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function votes()
    {
        return $this->morphMany('App\Vote', 'voteable');
    }

    public function seconds()
    {
        return $this->hasMany(Comment::class,'first_depth_id');
    }

Vote

    public function voteable()
    {
        return $this->morphTo();
    }

    public function user()
    {
        return $this->belongsTo(User::class);
    }

1直接用模型查詢評論及使用者的資料,資料型別也符合前端的要求

直接用sql去查文章的評論及使用者(不建議),因為用了7條sql

 $posts = Post::with(['comments'=>function ($query){
        $query->where('parent_id',null)->with(['user','seconds'=>function($query){
            $query->with('user','parent.user');
        }]);
    }])->get();

debug 顯示
file
返回到前端的資料
file

2查詢出所有評論及使用者,再去解析資料,返回前端。

該查詢用到三條sql(建議)

$posts = Post::with('comments','comments.user')->get();
$posts = collect($posts->toArray())->map(function ($post){
    $nestedKeys = [];
    $post['comments'] = array_column($post['comments'], null, 'id');
    foreach ($post['comments'] as $key=>$comment){
        if(!$parent_id=$comment['parent_id']){
            continue;
        }
        if (array_key_exists($first_depth_id=$comment['first_depth_id'], $post['comments'])) {
            if(!isset($post['comments'][$first_depth_id]['seconds'])){
                $post['comments'][$first_depth_id]['seconds'] = [];
            }
            $comment['parent']=$post['comments'][$parent_id];
            $post['comments'][$first_depth_id]['seconds'][] = $comment;
            $nestedKeys[]=$key;
        }else{
            $nestedKeys[]=$key;
        }
    }
    foreach ($nestedKeys as $val){
        unset($post['comments'][$val]);
    }
    return $post;
});

debug
file
返回到前端的資料,可以看到和上方的返回資料是一樣的,而這個只用了三條sql
file

由於點贊沒有無限極的影響,所以實現起來比較簡單

直接用模型實現

在評論的基礎上加上點贊和點讚的使用者即可(不建議,因為sql增加到12條)

$posts = Post::with(['comments'=>function ($query){
            $query->where('parent_id',null)->with(['votes'=>function($query){
                $query->with('user');
            },'user','seconds'=>function($query){
                $query->with(['user','parent.user','votes'=>function($query){
                    $query->with('user');
                }]);
            }]);
        },'votes'=>function($query){
            $query->with('user');
        }])->get();

debug
file
返回的資料
file

先查出總資料再去解析

在評論的基礎上加個點贊即可,用了7條sql(建議)

$posts = Post::with('comments','comments.user','votes.user','comments.votes.user')->get();
$posts = collect($posts->toArray())->map(function ($post){
    $nestedKeys = [];
    $post['comments'] = array_column($post['comments'], null, 'id');
    foreach ($post['comments'] as $key=>$comment){
        if(!$parent_id=$comment['parent_id']){
            continue;
        }
        if (array_key_exists($first_depth_id=$comment['first_depth_id'], $post['comments'])) {
            if(!isset($post['comments'][$first_depth_id]['seconds'])){
                $post['comments'][$first_depth_id]['seconds'] = [];
            }
            $comment['parent']=$post['comments'][$parent_id];
            $post['comments'][$first_depth_id]['seconds'][] = $comment;
            $nestedKeys[]=$key;
        }else{
            $nestedKeys[]=$key;
        }
    }
    foreach ($nestedKeys as $val){
        unset($post['comments'][$val]);
    }
    return $post;
});

debug 增加的4條sql是不可避免的
file
返回的資料
file

總結

一般來說查詢sql的時間,要多於程式解析的時間,所以把需要用到的資料,查詢出來,再去由程式去解析成相應的資料型別,而不要用sql去實現。

NOT IS BECAUSE I WANT TO WRITE,
BUT I WANT TO INCREASE,
SO I GO TO WRITE~~

相關文章