You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Eloquent中使用has()关联数据库字段作为阈值查询?

问题描述

我在Bottle与InventoryItem之间建立了如下关联:

InventoryItem.php:

public function bottles(): HasMany
{
   return $this->hasMany(InventoryItemBottle::class);
}

我需要查询bottles数量大于自身JSONB类型info字段中high_level_warning阈值的InventoryItem,当前查询代码如下(标注出问题行):

->when(
    $filters['filter'] === 'show_above_max_threshold',
    fn (Builder $query): Builder => $query->where(function (Builder $query): Builder {
        return $query->whereColumn('info->quantity', '>', 'info->high_level_warning');
    })
    ->orWhere(function (Builder $query): Builder {
        return $query->has('bottles', '>', 'info->high_level_warning'); // 此处遇到问题
    })
)

尝试用has()方法实现,但不知道如何将数据库中high_level_warning作为参数传入,求解决方法或思路。

解决思路与方法

has()方法无法直接引用当前模型的字段作为比较值,可通过以下几种方式实现需求:

方法一:子查询统计关联数量并比较

通过子查询算出每个InventoryItem对应的bottles数量,再和info->high_level_warning做字段间比较:

->when(
    $filters['filter'] === 'show_above_max_threshold',
    fn (Builder $query): Builder => $query->where(function (Builder $query): Builder {
        return $query->whereColumn('info->quantity', '>', 'info->high_level_warning');
    })
    ->orWhere(function (Builder $query): Builder {
        // 子查询统计每个InventoryItem的bottles数量
        $subQuery = InventoryItemBottle::selectRaw('count(*)')
            ->whereColumn('inventory_item_id', 'inventory_items.id');
        
        // PostgreSQL语法,MySQL替换为JSON_UNQUOTE(JSON_EXTRACT(info, '$.high_level_warning'))
        return $query->whereRaw('? > (info->>\'high_level_warning\')', [$subQuery]);
    })
)

方法二:Exists子查询判断

用exists子查询直接在数据库层面判断关联数量是否超过阈值,性能更优:

->when(
    $filters['filter'] === 'show_above_max_threshold',
    fn (Builder $query): Builder => $query->where(function (Builder $query): Builder {
        return $query->whereColumn('info->quantity', '>', 'info->high_level_warning');
    })
    ->orWhereExists(function (Builder $subQuery) {
        $subQuery->select(DB::raw(1))
            ->from('inventory_item_bottles')
            ->whereColumn('inventory_item_id', 'inventory_items.id')
            ->groupBy('inventory_item_id')
            ->havingRaw('count(*) > (inventory_items.info->>\'high_level_warning\')');
    })
)

方法三:withCount结合Having筛选

先预加载关联数量字段,再通过havingRaw做字段比较:

->when(
    $filters['filter'] === 'show_above_max_threshold',
    fn (Builder $query): Builder => $query->withCount('bottles')
        ->where(function (Builder $query): Builder {
            return $query->whereColumn('info->quantity', '>', 'info->high_level_warning');
        })
        ->orHavingRaw('bottles_count > (info->>\'high_level_warning\')')
)

内容的提问来源于stack exchange,提问作者Riza Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 20:05:30