4

I am trying to Order the Posts table by the number of votes a Post has got. The votes are stored in an other table

(Votes: post_id, user_id, vote_type)

Post-Model:

class Post extends Model
{
    public function user()
    {
      return $this->hasOne(User::class);
    }

    public function votes()
    {
      return DB::table('votes')->where('post_id','=',$this->id)->sum('vote_type');
    }
}

The votes functions returns the number of votes a post has recieved(The Votes a stored in a seperate table)

Now I am trying to order all the Posts by the number of votes they have got.

Post::get()->sortBy('votes');

This returns follwing Error:

Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation

I would be thankful about any help to fix this!

3 Answers 3

4

give it a try

Post::get()->sortBy(function($query){
return $query->votes();
});

Alternative

You can use withCount() as it will place a {relation}_count column on your resulting models.

Post::withCount(['votes'])
->orderBy('votes_count')
->get()

For Pagination

Refer docs for more details on paginations

Post::withCount(['votes'])
->orderBy('votes_count')
->paginate();
Sign up to request clarification or add additional context in comments.

3 Comments

The first solution doesn't work: It return following error: Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation This is because the votes() method returns an integer.
try now I have forgot () there
Thanks! This worked. Do you know if there is any possability to paginate the result, as it is an instance of collection
0

Add the following function in your Post Model

 protected static function boot()
    {
        parent::boot();
        static::addGlobalScope('voteCount', function ($builder) {
            $builder->withCount('votes');
        });
    }

Now, each of your post model will always have a voteCount value and You can sort on that.

In your controller, use:

Post::get()->sortBy('voteCount');

Keep in mind that this will always return a votesCount with the PostModel, but I'm assuming it will be required as it usually does in this kind of applications.

Comments

-1

If you want to sort votes as a attribute you have to to make it to be attribute by adding getVotesAttribute() method in your Post Model.

class Post extends Model
{
    public function user()
    {
      return $this->hasOne(User::class);
    }

    public function getVotesAttribute()
    {
      return DB::table('votes')->where('post_id','=',$this->id)->sum('vote_type');
    }
}

3 Comments

When you will want to display last 100 posts and their votes, will you execute this query for each post you want to print on screen? How will you sort it?
@BartłomiejSobieszek If you want to display 100 last posts just do Post::limit(100)->latest()->->get()->sortBy('votes'); what is the problem?
You sort it by query execution, it means you would execute the getVotesAttribute query 100 times as you need to make a query for each model to sort it out. If you don't see the problem then try to use 3 solutions like this on single page and think why loading of the pages takes more than 3 seconds

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.