37

I am trying to do a where clause on withCount method of laravel's eloquent query builder using this piece of code.

$posts = Post::withCount('upvotes')->where('upvotes_count', '>', 5)->get();

and this code is giving me this error.

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'upvotes_count' in 'where clause' (SQL: select , (select count() from upvotes where upvotes.upvoteable_id = posts.id and upvotes.upvoteable_type = App\Post) as upvotes_count from posts where upvotes_count > 5)

So from what I can guess is that upvotes_count isn't selected and hence the column is not being found, BUT if I execute this piece of code.

$posts = Post::withCount('upvotes')->get();

Then I am getting this output.

{
"id": 1,
"user_id": 15,
"title": "Voluptatum voluptas sint delectus unde amet quis.",
"created_at": "2016-10-07 13:47:48",
"updated_at": "2016-10-07 13:47:48",
"upvotes_count": 7
},
{
"id": 2,
"user_id": 2,
"title": "Molestiae in labore qui atque.",
"created_at": "2016-10-07 13:47:48",
"updated_at": "2016-10-07 13:47:48",
"upvotes_count": 2
},

Which basically means that upvotes_count is being selected, hence i am really confused about how to solve this problem.

(More options that I tried so far are given below with the respective error associated to it.)

$posts = Post::where('id', $id)->withCount(['upvotes' => function($query) {
        $query->where('upvotes_count', '>', 5);
    }])->get();

error.

SQLSTATE[42S22]: Column not found: 1247 Reference 'upvotes_count' not supported (forward reference in item list) (SQL: select , (select count() from upvotes where upvotes.upvoteable_id = posts.id and upvotes.upvoteable_type = App\Post and upvotes_count > 5) as upvotes_count from posts where id = 1)

code.

$posts = Post::where('id', $id)->with(['upvotes' => function($query) {
        $query->select('upvoteable_id AS upvotes_count');
    }])->where('upvotes_count', '>', 5)->get();

AND

$posts = \App\Post::where('id', $id)->with(['upvotes' => function($query) {
        $query->selectRaw('upvoteable_id AS upvotes_count');
    }])->where('upvotes_count', '>', 5)->get();

error.

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'upvotes_count' in 'where clause' (SQL: select * from posts where id = 1 and upvotes_count > 5)


I just want to use where clause on a count() method which is in a relationship with a parent model.

slapbot
  • 627
  • 1
  • 6
  • 17

6 Answers6

43

You can achieve requested result by using:

$posts = Post::withCount('upvotes')
         ->having('upvotes_count', '>', 5)
         ->get();
Medin Piranej
  • 789
  • 1
  • 8
  • 10
  • 2
    I am still getting the error: column `upvotes_count` does not exist. I am not sure how this works since from my research it looks like the having clauses are executed before the select statements, therefore the alias `upvotes_count` is not yet defined. I am using Postgres. Does this only work for MySQL? Is there a way around this other than having to do a `havingRaw` to manually get the count again? – Stetzon Jul 18 '19 at 15:56
  • @Stetzon `withCount('upvotes')` should add `upvotes_count`, so you should add this, or if you still have this problem, send me the query and i will check it. – Medin Piranej Aug 08 '19 at 14:48
  • @Stetzon Remember that you cannot do where clauses on aggregated columns, You can however do having clauses, so make sure that you are not doing where there. – slapbot Sep 30 '19 at 08:34
  • 2
    I also have an error that the column doesn't exist with MySQL. – Nikolay Traykov Feb 23 '21 at 11:07
  • 1
    Same here, "Undefined column: 7 ERROR: column "users_count" does not exist". The thing is, "having()" is producing the error, "orderBy" works. – Miguelp25 May 27 '21 at 22:26
30

another good way to do this we can filter that separately and even assign an alias to that column name

$posts = Post::withCount([
    'upvotes', 
    'upvotes as upvotes_count' => function ($query) {
        $query->where('upvotes_count', '>', 5);
    }])
    ->get();

Now in blade you can do

$posts->upvotes_count
Yousef Altaf
  • 2,631
  • 4
  • 46
  • 71
10

I'm not sure if this was implemented after your question, but you can now do it like this

$posts = Post::has('upvotes','>',5)->get();
Salman Zafar
  • 3,844
  • 5
  • 20
  • 43
7

I think using has() is the best solution:

Post::has('upvotes','>',5)->withCount('upvotes')->get()

You could also use a filter:

Post::withCount('upvotes')->get()->filter(function($post) { return $post->upvotes_count > 5; })

You could also disable strict mode in config/database.php (probably not a good idea)

'strict' => false,

Post::withCount('upvotes')->having('upvotes_count','>',5)->get()

You could also try to add a groupBy clause (using having in strict mode), but this will likely require you to include every column in your table (due to 'ONLY_FULL_GROUP_BY'), which could break things if you ever add another column to your table, and probably won't work anyway because I think you need to include 'upvotes_count' in the groupBy and it seems to be a non grouping field.

Keith Turkowski
  • 751
  • 7
  • 11
  • 1
    Thanks, this worked perfectly. It allows a condition thanks to the has() function and the withCount allowed me to use an orderBy. Again, thank you a lot. – Miguelp25 May 29 '21 at 11:26
3

If you need to select only rows that the counter is greater than or equal to 1 you can try the following code:

$posts = Post::withCount('upvotes')
             ->havingRaw('upvotes_count')
             ->get();

I don't know if this is the best solution but it's an alternative. Another alternative would be get the posts and use array filter as mentioned in a comment above.

1

I ran into the same problem, and tried the same things you did. I'm guessing there is a way to replicate the SQL generated by the withCounts call but add a way to make xxx_counts available to a where clause, but I just filtered the resulting collection instead.

$allTags = Tag::withCount('articles')->get();

$usedTags = $allTags->filter(function ($value, $key) {
        return $value->articles_count > 0;
    });
BigMitch
  • 19
  • 2
  • 1
    It's been quite a time, and as I learnt more about sql, you can't do where clauses on the aggregate functions, hence upvotes_count column isn't found since it's aggregated and not selected. but the above problem can be solved using some advanced queries and grouping them together. – slapbot Mar 03 '17 at 20:21