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

Laravel9+Jenssegers MongoDB3.9使用withCount报Illegal offset type错误

Laravel 9 + Jenssegers/MongoDB 3.9 withCount 报 Illegal offset type 错误的解决方案

问题场景

在Laravel 9搭配Jenssegers/MongoDB 3.9环境中,执行以下查询代码时触发Illegal offset type错误,报错堆栈指向Jenssegers\Mongodb\Query\Builder.php第373行:

$subscription = Subscription
    ::getById($subscriptionId)
    ->withCount('userSubscriptions')
    ->firstOrFail();

调试确认:$this->columns数组中包含Illuminate\Database\Query\Expression对象,框架遍历该数组转换为MongoDB投影时,直接将对象作为数组键引发类型错误。

此外,尝试添加->select('*','user_subscriptions_count')后无运行时错误,但结果中未出现统计字段,调试发现$columns仅保留了*。

原因分析

Jenssegers/MongoDB 3.9版本的withCount实现存在兼容性缺陷:当查询列中包含Expression类型对象时,转换MongoDB投影的逻辑未做类型处理,直接将对象作为数组索引,触发PHP的非法偏移类型错误。

解决方案

方案1:手动实现关联统计(绕过withCount)

通过原生MongoDB聚合或关联查询手动计算统计值,避免依赖有问题的withCount方法:

方式A:使用关联查询+统计

$subscription = Subscription::getById($subscriptionId)
    ->leftJoin('user_subscriptions', 'subscriptions._id', '=', 'user_subscriptions.subscription_id')
    ->select('subscriptions.*', DB::raw('count(user_subscriptions._id) as user_subscriptions_count'))
    ->groupBy('subscriptions._id')
    ->firstOrFail();

方式B:使用MongoDB原生聚合管道

$subscription = Subscription::raw(function($collection) use ($subscriptionId) {
    return $collection->aggregate([
        ['$match' => ['_id' => new MongoDB\BSON\ObjectId($subscriptionId)]],
        [
            '$lookup' => [
                'from' => 'user_subscriptions',
                'localField' => '_id',
                'foreignField' => 'subscription_id',
                'as' => 'user_subscriptions'
            ]
        ],
        [
            '$addFields' => [
                'user_subscriptions_count' => ['$size' => '$user_subscriptions']
            ]
        ],
        ['$limit' => 1]
    ])->toArray()[0];
});

注:若模型主键不是ObjectId类型,需调整$match条件中的主键格式。

方案2:临时修复Jenssegers/MongoDB源码

修改Jenssegers\Mongodb\Query\Builder.php中处理列投影的逻辑,添加对Expression对象的解析:
找到遍历$this->columns转换投影的代码段(对应报错的第373行附近),替换为以下逻辑:

foreach ($this->columns as $key => $column) {
    // 处理Expression类型的列
    if ($column instanceof \Illuminate\Database\Query\Expression) {
        $column = $column->getValue($this->getConnection());
    }
    // 区分索引类型,正确设置投影
    if (is_numeric($key)) {
        $projection[$column] = 1;
    } else {
        $projection[$key] = $column;
    }
}

⚠️ 该方案仅作为临时修复,不建议长期使用,后续需跟进版本升级。

方案3:升级Jenssegers/MongoDB版本

查看Jenssegers/MongoDB官方仓库的issue和更新日志,确认是否有后续版本修复了withCount的兼容性问题。例如升级到4.x版本(需提前确认版本与Laravel 9的兼容性)。

验证

执行修复后的查询,确认user_subscriptions_count字段能正确返回关联数据的统计数量,且无类型错误抛出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 17:45:49