查询来自 Eloquent 的计数

Querying count from Eloquent

我在 eloquent 中有一个查询正确地计算了这里应有的计数:

$query = A::withCount(
        ['bs' =>
            function ($query) use ($from, $to) {
                $query->where(function ($query) use ($from) {
                    $query->whereDate('start', '<', $from)
                        ->whereDate('end', '>', $from);
                })->orWhere(function ($query) use ($to) {
                    $query->whereDate('start', '<', $to)
                        ->whereDate('end', '>', $to);
                })->orWhere(function ($query) use ($from, $to) {
                    $query->whereDate('start', '>', $from)
                        ->whereDate('end', '<', $to);
                });
        }])
        ->whereBetween('cmp1', [$min_cmp1, $max_cmp1])
        ->whereBetween('cmp2', [$min_cmp2, $max_cmp2])
        ->where('cmp3', '<=', $request->cmp3)
        ->where('cmp4', '<=', $request->cmp4)
        ->with('more_relations');

    return AResource::collection($query->paginate(5));

这转到 API 控制器。我将其用于 Vue 的前端分页。我想使用计数过滤掉所有 bs_count 为 0 的 A,但是链接 where 子句不起作用,因为它是一个聚合,并且它 returns 一个错误因为找不到名为 bs_count 的列。我发现解决方案是使用 having 子句。我找到了这段代码,但是当我尝试转换它时,它不起作用,返回相同的错误,找不到名为 bs_count.

的列
DB::table('bs')
->select('*', DB::raw('COUNT(*) as bs_count'))
->groupBy('a_id')
->having('bs_count', '=' , 0);

这没有在计数上添加额外的查询,因为我想先试试看它是否有效,但事实并非如此。

having 子句是否正确?我想我需要使用 Eloquent 而不是 DB::table() 语法,因为资源构建器使用模型结构来构建资源响应。

总而言之,我正在尝试使用我在第一个查询中计算的计数,并针对它进行查询:where bs_count = 0。有没有办法在 Laravel 中执行此操作并且仍然能够将结果传递给 API 资源?

使用 HAVING 子句是正确的方法。

问题是 Laravel 分页本身不支持 HAVING 子句。
您必须手动创建 pagniator:
How to use paginate() with a having() clause when column does not exist in table

您使用 DB 的测试查询不起作用,因为分组时您不能 select 所有列:

->select('a_id', DB::raw('COUNT(*) as bs_count'))
正如我发现的那样,

Laravel 确实有一个 built-in 解决方案。 From the docs,我找到了函数whereHas()whereDoesntHave()。这些函数允许您传递一个闭包,以根据它在幕后进行的计数来过滤行。我如何调整我以前的解决方案是:

$query = A::whereDoesntHave(
    'bs', 
        function ($query) use ($from, $to) {
            $query->where(function ($query) use ($from) {
                $query->whereDate('start', '<', $from)
                    ->whereDate('end', '>', $from);
            })->orWhere(function ($query) use ($to) {
                $query->whereDate('start', '<', $to)
                    ->whereDate('end', '>', $to);
            })->orWhere(function ($query) use ($from, $to) {
                $query->whereDate('start', '>', $from)
                    ->whereDate('end', '<', $to);
            });
    )
    ->whereBetween('cmp1', [$min_cmp1, $max_cmp1])
    ->whereBetween('cmp2', [$min_cmp2, $max_cmp2])
    ->where('cmp3', '<=', $request->cmp3)
    ->where('cmp4', '<=', $request->cmp4)
    ->with('more_relations');

return AResource::collection($query->paginate(5));

这会根据传递的查询自动计算 B,并且只有 returns 行的计数为零,这正是我所需要的。