lumen with mongodb :getting error : Call to a member function prepare() on null

Viewed 1422

I am working with lumen and mongodb

I want to get (total unread) and total messages count based on folder

my mongodb query is like below,

$totalEmails = DB::connection('mongodb')
        ->select("sum(if(is_read==0,1,0)) as unread", "count(message_id) as total", "folder_id")
        ->collection('email_message')
        ->where('email_account_id', (int)$request->email_account_id)
        ->where('status', "Active")
        ->groupBy("folder_id")
        ->get();

it gives me error as below,

FatalErrorException in Connection.php line 333:
Call to a member function prepare() on null

please help me to resolve this issue.thank you.

I have resolve that error by change my query as below,

$totalEmails = DB::connection('mongodb')            
            ->collection('email_message')
            ->select("sum(if(is_read==0,1,0)) as unread", "count(message_id) as total", "folder_id")
            ->where('email_account_id', (int)$request->email_account_id)
            ->where('status', "Active")
            ->groupBy("folder_id")
            ->get();

but it not gives me expected result,

it give me result as below,

[_id] => Array
            (
                [folder_id] => 5bee461e19f043020c001844
            )

    [folder_id] => 5bee461e19f043020c001844
    [sum(if(is_read==0,1,0)) as unread] => 
    [count(message_id) as total] => 

but my expectation is

[_id] => Array
            (
                [folder_id] => 5bee461e19f043020c001844
            )

    [folder_id] => 5bee461e19f043020c001844
    [unread] => 2
    [total] => 10

can you tell me where is wrong in query???

If I am using below query

$totalEmails = DB::connection('mongodb')
    ->selectRaw("sum(if(is_read==0,1,0)) as unread", "count(message_id) as total", "folder_id")
    ->collection('email_message')
    ->where('email_account_id', (int)$request->email_account_id)
    ->where('status', "Active")
    ->groupBy("folder_id")
    ->get();

it gives me error like,

ErrorException in Builder.php line 245:
Argument 2 passed to Illuminate\Database\Query\Builder::selectRaw() must be of the type array, string given,

If I am using below query,

 $totalEmails = DB::connection('mongodb')        
        ->collection('email_message')
        ->selectRaw("sum(if(is_read==0,1,0)) as unread,count(message_id) as total,folder_id")
        ->where('email_account_id', (int)$request->email_account_id)
        ->where('status', "Active")
        ->groupBy("folder_id")
        ->get();

it gives me result like,

[_id] => Array
                (
                    [folder_id] => 5bee461e19f043020c001844
                )

            [folder_id] => 5bee461e19f043020c001844
            [sum(if(is_read==0,1,0)) as unread,count(message_id) as total,folder_id] => 

please help me to get my expected result

2 Answers

I am not sure if this is what is causing your issue but you have an error in your code

It should be:

$totalEmails = DB::connection('mongodb')
    ->selectRaw("sum(if(is_read==0,1,0)) as unread, count(message_id) as total, folder_id")
    ->collection('email_message')
    ->where('email_account_id', (int)$request->email_account_id)
    ->where('status', "Active")
    ->groupBy("folder_id")
    ->get();

The selectRaw is needed to include raw code in the select. Here is the docs for more info

https://laravel.com/docs/5.5/queries#raw-expressions

This is quite a complex query to execute and very hard to produce with the laravel methods as far as I know, so I would recommend a raw query by using $aggregate like the following example:

$totalEmails = DB::connection("mongodb")
    ->collection("email_message")
    ->raw(function ($collection) {
        return $collection->aggregate(
            [
                [
                    "\$match" => [
                        "email_account_id" => (int)$request->email_account_id,
                        "status" => "active"
                    ]
                ],
                [
                    "\$group" => [
                        "_id" => [
                            "folder_id" => "\$folder_id"
                        ],
                        "unread" => [
                            "\$sum" => [
                                "\$switch" => [
                                    "branches" => [
                                        ["case" => [
                                            "\$eq" => [
                                                "\$is_read", '0,1,0'
                                            ]
                                        ],
                                            "then" => 1
                                        ]
                                    ],
                                    "default" => 0
                                ]
                            ]
                        ],
                        "total" => [
                            "\$sum" => 1
                        ]
                    ]
                ]
            ]
        );
    });

$collectedResult = array();
foreach ($result as $k => $v) {
    $collectResult[] = $v->jsonSerialize();
}

return $collectedResult;

I have formatted it to be as readable as possible and I will try to explain every part of the query as well as possible so you know what it does.

By using the raw statement we can use the aggregate() function which simulates the mongo $aggregate.

First we want to filter on email_account_id which is done with the $match method, note that the $ is escaped because otherwise php will interpret it as a variable.

After that we need to perform the group by which is done with this part:

"_id" => [
      "folder_id" => "\$folder_id"
]

This will create the _id column with in it an array with the key folder_id and will collect all unique values of the DB column 'folder_id' into the value.

Thus this part will produce an array of elements with unique folder_ids, then the unread and total messages will have to be counted for these folders.

The total is simple and is done with the $sum operator. The unread part is a bit more complex because this will need to filter on the is_read operator. Which is done with a switch statement and a default value of 0 (don't count when condition fails).

The raw query will return a MongoCursor so the last part is to collect these results

I hope this helps you and if anything is unclear please let me know.

Related