0
votes

I would like to create a withCount subquery for this model.

Thanks to Iqbal Butt I have this snippet for getting the count.

$count = Action::select('article_id as assigned');

if (!empty($action_type_id))
{
    $count = $count->where('action_type_id', $action_type_id);
}

if (!empty($set_id))
{
    $count = $count->where('set_id', $set_id);
}

$count = $count->distinct('article_id')->count('article_id');

I would like to execute it like this, but I feel this is painfully flawed.

Clarification edit


I have a many to many relationship of sets to articles.

Each article has a number of actions.

The actions can have a variety of action types.

I need to count the types of actions for each article in a given set.


$sets = Set::withCount(['actions' => function ($q) use ($action_type_id, $set_id) {

    $q->select('article_id as assigned');

    if (!empty($action_type_id))
    {
        $q->where('action_type_id', $action_type_id);
    }

    if (!empty($set_id))
    {
        $q->where('set_id', $set_id);
    }

    $q->distinct('article_id')
      ->count('article_id'); 
    // I believe this is executing inner query
}])

->get();

return $sets;   

This gives me the error, more then likely because the inner query is executing and without the outer query.

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'sets.id' in 'where clause' (SQL: select count(distinct article_id) as aggregate from actions where sets.id = actions.set_id and action_type_id = 1 and set_id = 1)


Edit per comments


Article Model

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    /**
     * Get the sets for the article.
     */
    public function sets()
    {
        return $this->belongsToMany(Set::class);
    }

    public function actions()
    {
        return $this->hasMany(Action::class);
    }
}

Set Model

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Set extends Model
{
    /**
     * Get the articles for the set.
     */
    public function articles()
    {
        return $this->belongsToMany(Article::class);
    }

    public function actions()
    {
        return $this->hasMany(Action::class);
    }
}

Action Model

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Action extends Model
{
    /**
     * Get the set that owns the action.
     */
    public function set()
    {
        return $this->belongsTo(Set::class);
    }
    /**
     * Get the article that owns the action.
     */
    public function article()
    {
        return $this->belongsTo(Article::class);
    }
}

Database

actions

id
set_id
article_id
action_type_id 

sets

id
name

articles

id
name

article_set

id
set_id
article_id
1
It's hard to know what you are trying to do without more details about your database structure. Can you post the migrations / models of the tables involved? Also, you might be interested in laravel.com/docs/5.8/queries#conditional-clauses for conditionally adding clauses to your eloquent queries.Peter
@Peter Added more info, thankswhoacowboy
OK thanks. Can you provide more details on what exactly you are trying to get with your query? A count of the articles for a given set? Sorry I'm not clear on what you need.Peter
Sure, I have edited my question. When looking through my question with fresh eyes, the action_id was very confusing so I changed it to action_type_id. Thanks again.whoacowboy

1 Answers

1
votes

Here is something that will get the data you need although it uses the returned collection to calculate the count.

$articles = Set::find($set_id)
    ->articles()
    ->with('actions')
    ->get()
    ->map(function($article){
        $article->action_type_count = $article->actions->unique('action_type')->count();
        return $article;
    });

This will give you a collection of articles. The action type count is in a property action_type_count on each article in the collection. So to get the first article's action type count:

$articles->first()->action_type_count;