labrat's avatar
Level 2

Sorting data by accessor column/computed property?

Hey all. I'm trying to solve a 'column not found' issue in my program. I have an accessor on my Conversation model that gets the outboundMessagesCount and another that gets the outboundCallsCount, then a totalOutboundContactCount that adds those two values. Since these aren't columns in my table, I'm not able to sort the returning data from my query directly on these values, but I should be able to use raw sql in my backend to get these values and sort my data based on the data returned, right? OR do I have to have a column in my database to sort on? Thanks!

0 likes
1 reply
LaryAI's avatar
Level 58

To solve the issue of sorting data by an accessor column or computed property in your Laravel application, you can use a combination of raw SQL and Eloquent to achieve this. Since the values you want to sort by are not actual columns in your database, you can use a subquery to calculate these values and then sort by the result of that subquery.

Here's a step-by-step solution:

  1. Define the Accessors in Your Model: Ensure you have the accessors defined in your Conversation model for outboundMessagesCount, outboundCallsCount, and totalOutboundContactCount.

    class Conversation extends Model
    {
        public function getOutboundMessagesCountAttribute()
        {
            // Logic to calculate outbound messages count
        }
    
        public function getOutboundCallsCountAttribute()
        {
            // Logic to calculate outbound calls count
        }
    
        public function getTotalOutboundContactCountAttribute()
        {
            return $this->outboundMessagesCount + $this->outboundCallsCount;
        }
    }
    
  2. Use a Subquery to Calculate the Total Outbound Contact Count: You can use a subquery to calculate the totalOutboundContactCount and then sort by this value.

    use Illuminate\Support\Facades\DB;
    
    $conversations = Conversation::select('*')
        ->selectSub(function ($query) {
            $query->select(DB::raw('outbound_messages_count + outbound_calls_count'))
                  ->from('conversations as sub')
                  ->whereColumn('sub.id', 'conversations.id')
                  ->limit(1);
        }, 'total_outbound_contact_count')
        ->orderBy('total_outbound_contact_count', 'desc')
        ->get();
    
  3. Alternative Approach Using Eloquent Accessors: If you prefer to keep the logic within Eloquent, you can use a custom query scope to achieve the same result.

    class Conversation extends Model
    {
        // Accessors as defined earlier
    
        public function scopeWithTotalOutboundContactCount($query)
        {
            return $query->select('*')
                ->selectSub(function ($query) {
                    $query->select(DB::raw('outbound_messages_count + outbound_calls_count'))
                          ->from('conversations as sub')
                          ->whereColumn('sub.id', 'conversations.id')
                          ->limit(1);
                }, 'total_outbound_contact_count');
        }
    }
    
    // Usage
    $conversations = Conversation::withTotalOutboundContactCount()
        ->orderBy('total_outbound_contact_count', 'desc')
        ->get();
    

In both approaches, the key is to use a subquery to calculate the totalOutboundContactCount and then sort by this computed value. This way, you don't need to add a new column to your database, and you can still sort your data based on the computed property.

Please or to participate in this conversation.