Adding withCount in mongodb request I got Illegal offset type error

645 Views Asked by At

In laravel 9 with MongoDB(jenssegers/mongodb 3.9) I added withCount in request :

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

and got error :

[2022-08-16 14:02:18] local.ERROR: Illegal offset type {"userId":"62fb9ff9f74eb576f803a7b2","exception":"[object] (TypeError(code: 0): Illegal offset type at Project/vendor/jenssegers/mongodb/src/Query/Builder.php:373)
[stacktrace]
#0 Project/vendor/jenssegers/mongodb/src/Query/Builder.php(201): Jenssegers\\Mongodb\\Query\\Builder->getFresh()
#1 Project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(698): Jenssegers\\Mongodb\\Query\\Builder->get()
#2 Project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(682): Illuminate\\Database\\Eloquent\\Builder->getModels()
#3 Project/vendor/laravel/framework/src/Illuminate/Database/Concerns/BuildsQueries.php(296): Illuminate\\Database\\Eloquent\\Builder->get()
#4 Project/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(582): Illuminate\\Database\\Eloquent\\Builder->first()
#5 Project/app/Http/Controllers/Admin/SubscriptionController.php(162): Illuminate\\Database\\Eloquent\\Builder->firstOrFail()
#6 Project/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): App\\Http\\Controllers\\Admin\\SubscriptionController->edit()
#7 Project/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): Illuminate\\Routing\\Controller->callAction()
#8 Project/vendor/laravel/framework/src/Illuminate/Routing/Route.php(261): Illuminate\\Routing\\ControllerDispatcher->dispatch()
#9 Project/vendor/laravel/framework/src/Illuminate/Routing/Route.php(204): Illuminate\\Routing\\Route->runController()
#10 Project/vendor/laravel/framework/src/Illuminate/Routing/Router.php(725): Illuminate\\Routing\\Route->run()

I tried to debug this error in src/Query/Builder.php file:

$columns = [];

// Convert select columns to simple projections.
\Log::info(varDump($this->columns, ' -1 $this->columns::'));
foreach ($this->columns as $column) {
    $columns[$column] = true; // THIS LINE RAISED ERROR 
}

I see in log file:

[2022-08-16 14:02:18] local.INFO: Array(2) : -1 $this->columns:: : Array
(
    [0] => subscriptions.*
    [1] => Illuminate\Database\Query\Expression Object
        (
            [value:protected] => (select "subscription_id" from "user_subscriptions" where "subscription_id" exists ?) as "user_subscriptions_count"
        )

)

Relation is set in app/Models/Subscription.php :

public function userSubscriptions()
{
    return $this->hasMany('App\Models\UserSubscription', 'subscription_id', '_id');
}

This relation is used in boot method :

protected static function boot()
{
    parent::boot();
    static::deleting(function ($subscription) {
        $subscription->userSubscriptions()->delete();
    });

}

and all related userSubscriptions are deleted ok. Error only on withCount.

How that can be fixed ?

MODIFIED BLOCK # 1:

After some attempts I managed to run the reqiest with adding “->select” into the request

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

I do not have any runtime error, but in resulting data there no “user_subscriptions_count” or any “count” fields.

I tried to debug source code by error trace and see that, say in vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php line 698 var $columns has values::

 Array
(
    [0] => *
)

Have anybody used withCount with jenssegers/mongodb ?
Thanks!

1

There are 1 best solutions below

0
On

This seems to be a limitation/bug in the package as seen here https://github.com/jenssegers/laravel-mongodb/issues/1339

The exact error means that it tries to assign an object (the Query\Expression object) as an array key which is obviously invalid (you can only use scalar values e.g. ints/strings). So it seems it simply isn't supported.

There appears to be somewhat of a workaround by using Laravel's $appends property e.g. $appends = ['userSubscriptions'];, however this does not eager load that data so it is inefficient to use this for large datasets.

If you have an idea for a solution you can create a PR for the package (but you need some in-depth knowledge about Laravel's query classes)