MongoDB count with queries - mongodb

I've been working on a project that now needs to use the MongoDB count function (MySQL equivalent's count function). The code I have at the moment is
$filter = ["username" => array('$ne' => null, '$ne' => '')];
$options = ["projection" => ['username' => true]];
$query = new MongoDB\Driver\Query($filter, $options);
$cursor = $mongo->executeQuery('mongodbLog.logs', $query);
I want to add the count functionality in the $filter array, but I can't get it to work correctly.
I want my MongoDB query to get the same result as this MySQL query: "SELECT username,count(*) FROM mysqlLog WHERE username <> '' GROUP BY username".
All I have managed so far is the where clause equivalent and now I'm stuck.

You can try the below aggregation.
Aggregation Stages - $match - $group - $project
$pipeline =
[
[
'$match' =>
[
'$and' =>
[
['username' => ['$ne' => null]],
['username' => ['$ne' => '']],
],
],
],
[
'$group' =>
[
'_id' => '$username',
'count' => ['$sum' => 1],
],
],
[
'$project' =>
[
'_id' => 0,
'username' => 1,
'count' => 1,
],
],
];
$command = new \MongoDB\Driver\Command([
'aggregate' => 'logs',
'pipeline' => $pipeline
]);
$cursor = $mongo->executeCommand('mongodbLog', $command);

Related

$match query not working for lookup array in mongodb

I have two tables in mongodb database
activityCountTbl contains data like
{
"_id": ObjectId("5c234f7e3250041280000ca3"),
"activityId": ObjectId("5c0e27ee590a06bf08003c33"),
"weekgroupId": ObjectId("5bfbddbcbb2c5645f8001495"),
"squadronId": ObjectId("5bfc7b7ebb2c56c320002a0a"),
"attendingCount": NumberInt(6),
....
}
{
"_id": ObjectId("5c234f7e3250041280000ca3"),
"activityId": ObjectId("5c0e27ee590a06bf08003c33"),
"weekgroupId": ObjectId("5bfbddbcbb2c5645f8001496"),
"squadronId": ObjectId("5bfc7b7ebb2c56c320002a0a"),
"attendingCount": NumberInt(6),
....
}
squadronTbl contains data like
{
"_id": ObjectId("5c19ccb7590a060691000554"),
"squadronCode": "336",
"squadronName": "336TRS",
}
{
"_id": ObjectId("5c19ccb7590a060691000556"),
"squadronCode": "337",
"squadronName": "337TRS",
}
I am storing count details of a particular activity of a weekgroup in activityCountTbl. I am performing lookup on squadronTbl with activityCountTbl
for fetching squadrons details of a particular weekgroup. The below code is not working.
When I comment/delete the $query code, it fetches all the squadrons of all weekgroups.
$query = ["ActivityArray.weekgroupId" => new MongoDB\BSON\ObjectID("5bfbddbcbb2c5645f8001495"), "ActivityArray.funRun" => "Yes"];
$pipeline = array(
[
'$match' => $query
],
[
'$lookup' => [
'from' => 'activityCountTbl',
'localField' => '_id',
'foreignField' => 'squadronId',
'as' => 'ActivityArray'
]
],
['$project' => [
'_id' => 1.0,
'squadronName' => 1.0,
'ActivityArray' => 1.0
]],
);
return $this->db->squadronTbl->aggregate($pipeline)->toArray();
Please help !!!
$query = ["ActivityArray.weekgroupId" => new MongoDB\BSON\ObjectID("5bfbddbcbb2c5645f8001495"), "ActivityArray.funRun" => "Yes"]
$pipeline = array(
[
'$match' => []
],
[
'$lookup' => [
'from' => 'activityCountTbl',
'localField' => '_id',
'foreignField' => 'squadronId',
'as' => 'ActivityArray'
]
],
[
'$match' => $query
],
['$project' => [
'_id' => 1.0,
'squadronName' => 1.0,
'ActivityArray' => 1.0
]],
);
something like that

MongoDB query $lookup with prefix

I have two collection rounds and summaries
A record in rounds looks like
{
"_id": "2018-04",
"name": "Round 2018-04"
}
A record in summaries look like
{
"phase": "round:2018-04",
"userId": NumberLong(66325),
}
I want to query summaries and lookup into rounds joining based on phase of summaries into _id of rounds
PROBLEM: It will be pretty simple if there was no prefix of round: in phase.
Is there anyway to do this?
This is my code so far.
$cursor = $this->mongo->selectCollection('summaries')->aggregate([
array('$match' => []),
array(
'$lookup' => [
'from' => 'rounds',
'localField' => 'phase',
'foreignField' => '_id',
'as' => 'roundDetail'
]
),
array(
'$unwind' => '$roundDetail',
),
array(
'$project' => [
'userId' => 1,
'roundDetail.name' => 1
]
)
]);
MongoDB version 3.4.16
You can use substrBytes to remove characters from the string.
$cursor = $this->mongo->selectCollection('summaries')->aggregate([
array('$match' => []),
array('$addFields' => [ 'phase' => [ '$substrBytes' => [ '$phase', 6, 7 ] ] ] ),
array(
'$lookup' => [
'from' => 'rounds',
'localField' => 'phase',
'foreignField' => '_id',
'as' => 'roundDetail'
]
),
array(
'$unwind' => '$roundDetail',
),
array(
'$project' => [
'userId' => 1,
'roundDetail.name' => 1
]
)
])

add where condition in jensseger mongodb with lookup

I have code like this:
$users = User::raw(function ($collection) use($profession, $userId, $skip, $pageSize) {
return $collection->aggregate([
[
'$lookup' => [
'from' => 'user_profile',
'localField' => 'uid',
'foreignField' => 'user_id',
'as' => 'profile'
]
],
[
'$match' => [
'profile.field_of_work' => $profession['id'],
'uid' => ['$ne' => $userId]
],
],
['$skip' => $skip],
['$limit' => $pageSize]
]);
});
from there, how to add where clause like this:
::where('name', 'like', '%test%');
I dont know how to using lookup in mongodb and I just know the basic pattern of eloquent.
Thank you

PHP mongo - projection on particular array value

I have the following query:
$aggregate = [
['$unwind' => '$positions'],
['$match' => ['positions.banner_params.project_location_id' => (int)$projectId]],
[
'$project' => [
'page_id' => '$_id',
'position_id' => '$positions.id',
'page' => [
'website_id' => '$website_id',
'rate_tic' => '$rate_tic',
],
'banner_params' => [
'title' => '$positions.banner_params.title',
'tmpl_id' => '$positions.banner_params.tmpl_id'
],
'tmpl' => '$positions.tmpls',
'_id' => 0
]
],
];
$rows = $collection->aggregate($aggregate);
It returns such result:
[0] => Array
(
[page_id] => MongoId Object
(
[$id] => 5527a3a276098d86ae9aa3aa
)
[position_id] => 1
[page] => Array
(
[website_id] => 41
[rate_tic] => 10
)
[banner_params] => Array
(
[title] => My Title
[tmpl_id] => 2
)
[tmpl] => Array
(
[0] => Array
(
[id] => 1
[width] => 500
[height] => 100
)
[1] => Array
(
[id] => 2
[width] => 160
[height] => 400
)
[2] => Array
(
[id] => 7
[width] => 384
[height] => 115
)
)
)
How do I get into the tmpl only the template that match the banner_params.tmpl_id?
first let me sure if i understand it correctly. you want to filter items in the [tmpl] => Array by [id].
you cannot do that directly as the [tmpl] is an embedded object however as the aggregate is a pipeline function you can convert the current output the way you can filter and with $unwind then filter it again with $match and finally get the document as you wanted with $group. Something like below code should achieve what you want;
$aggregate = [
['$unwind' => '$positions'],
['$match' => ['positions.banner_params.project_location_id' => (int)$projectId]],
[
'$project' => [
'page_id' => '$_id',
'position_id' => '$positions.id',
'page' => [
'website_id' => '$website_id',
'rate_tic' => '$rate_tic',
],
'banner_params' => [
'title' => '$positions.banner_params.title',
'tmpl_id' => '$positions.banner_params.tmpl_id'
],
'tmpl' => '$positions.tmpls',
'_id' => 0
]
],
['$unwind' => '$tmpl'], // makes every item as a colection
['$match' => ['tmpl.id' => (int)$your id]], //filter the records
['$group' => ['_id' => '$page_id', tmpl:{$push:"$tmpl"} ]] // rebuild collection as you wanted you can use a compound _id if this is not enough
//if you don t want to see _id apply another projections to change it.
];
$rows = $collection->aggregate($aggregate);
Might have some errors but this is the logic you should implement.
EDIT:
There is also $redact DOC to remove items in sub documents please see the example.
Restricts the contents of the documents based on information stored in
the documents themselves.
Well, thanks to Onur TOPAL's advice I found the solution. One more $unvind followed by $redact did the job.
$aggregate = [
['$unwind' => '$positions'],
['$match' => ['positions.banner_params.project_location_id' => (int)$projectId]],
[
'$project' => [
'page_id' => '$_id',
'position_id' => '$positions.id',
'page' => [
'website_id' => '$website_id',
'rate_tic' => '$rate_tic',
],
'banner_params' => [
'title' => '$positions.banner_params.title',
'tmpl_id' => '$positions.banner_params.tmpl_id'
],
'tmpl' => '$positions.tmpls',
'_id' => 0
]
],
['$unwind' => '$tmpl'],
[
'$redact' => [
'$cond' => [
'if' => ['$eq' => ['$tmpl.id', '$banner_params.tmpl_id']],
'then' => '$$KEEP',
'else' => '$$PRUNE'
]
]
]
];

How to make this MongoDB aggregation return key:value?

I have this aggregation:
$out = $db->stats->aggregate (
array('$match' => $where),
,array( '$group' =>
array( "_id" => '$traffic.source',
'count'=> array('$sum' => 1)
)
)
,array( '$project' =>
array( "_id" => 0,
'type' => '$_id',
'count' => '$count'
)
)
);
which returns an array with:
[{type:sourceA, count:2},{type:sourceB, count:6}...]
Is it possible to make it return:
[sourceA:2, sourceB:6,....] without looping the array afterwords?