How to implement MongoDB query in Laravel 5? - mongodb

I created mongodb query which I have to use in laravel controller.
My query is
db.PMS.aggregate([
{ $match: { "PanelID": "A00898" } },
{
$project: { EventTS: 1, MainsPower: 1, }
},
{
$unwind: {
path: "$MainsPower",
includeArrayIndex: "arrayIndex",
preserveNullAndEmptyArrays: true
}
},
{
$project: {
MainsPower: 1,
timestamp: {
"$add": [
"$EventTS",
{ "$multiply": [ 60000, "$arrayIndex" ] }
]
}
}
}
]);
I tried to use this query in a laravel function but I am little confused. Please help me how to implement this query in laravel.

Perform raw expressions on the internal MongoCollection object to run the aggregation:
$result = DB => collection('PMS')->raw(function ($collection){
return $collection->aggregate(array(
array( '$match' => array( "PanelID" => "A00898" ) ),
array( '$project' => array( 'EventTS' => 1, 'MainsPower' => 1 ) ),
array(
'$unwind' => array(
'path' => "$MainsPower",
'includeArrayIndex' => "arrayIndex",
'preserveNullAndEmptyArrays' => true
)
),
array(
'$project' => array(
'_id' => 0,
'MainsPower' => 1,
'timestamp' => array(
"$add" => array(
"$EventTS",
array( "$multiply" => array( 60000, "$arrayIndex" ) )
)
)
)
)
));
});

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
]
)
])

Find on the basis of field of last element of embedded document in mongo db php

I have a collection studentTbl which contains records like
Record 1
"_id": ObjectId("5b45d89bbbc51e2c2c006973")
"first_name": "Pooja",
...
contact_details[
{
..
},
{
..
}
]
transport_details[
{
allotment_id:"68998546878",
..
status:"Inactive"
},
{
allotment_id:"25799856890",
..
status:"Active"
}
]
}
Record 2
"_id": ObjectId("5b45d89bbbc51e2c2533")
"first_name": "Poornima",
...
contact_details[
{
..
},
{
..
}
]
transport_details[
{
allotment_id:"68998546878",
..
status:"Inactive"
}
]
}
Record 3
"_id": ObjectId("5b45d89bbbc51e2c2c00646")
"first_name": "Poonam",
...
contact_details[
{
..
},
{
..
}
]
transport_details[
{
allotment_id:"68998546878",
..
status:"Inactive"
},
{
allotment_id:"25799856890",
..
status:"Active"
}
]
}
I am trying to tweak the below lines of code in order to fetch those students whose first_name or middle_name or last_name contains "poo" and inside the last element of embedded document transport_details, status should be "Active". How to write such a query which will find students on the name basis and traverse through the last element of embedded document transport_details and checks whether the status is active? For e.g in the above collection, pooja and poonam should be returned.
The code is like
// default if nothing is filled
$query = array("schoolId"=> new MongoDB\BSON\ObjectID($this->schoolId));
// if name = filled, class = null, year = null
if(!empty($this->name) && empty($this->academicYearName) && empty($this->programId))
{
$param = preg_replace('!\s+!', ' ', $this->name);
$arg = trim($param);
$query = array(
'$or' => array(
array("first_name" => new MongoDB\BSON\Regex($arg, 'i')),
array("middle_name" => new MongoDB\BSON\Regex($arg, 'i')),
array("last_name" => new MongoDB\BSON\Regex($arg, 'i')),
array("registration_temp_perm_no" => $arg)
),
"schoolId"=> new MongoDB\BSON\ObjectID($this->schoolId)
);
}
...
...
...
$pipeline = array(
array(
'$match' => $query
),
array(
'$lookup' => array(
'from' => 'programTbl',
'localField' => 'classId',
'foreignField' => '_id',
'as' => 'ClassDetails'
)
),
);
try
{
$cursor = $this->collection->aggregate($pipeline);
}
catch (Exception $e) {
}
return $cursor->toArray();
Note that the actual code contains more conditional $query variable...
You can use below query in 3.6.
array(
'$or' => array(
array("first_name" => new MongoDB\BSON\Regex("/poo/i")),
array("middle_name" => new MongoDB\BSON\Regex("/poo/i")),
array("last_name" => new MongoDB\BSON\Regex("/poo/i"))
),
"$expr" => array(
"$eq" => array(
array("$arrayElemAt" => array("$transport_details.status", -1)),
"Active"
)
)
);
You can add below stages in your pipeline
array(
"$match" => array(
"$expr" => array(
"$and" => [
array(
"$or" => [
array( "$eq" => [ array( "$strcasecmp" => [ "$first_name", "Poo" ] ), 1 ] ),
array( "$eq" => [ array( "$strcasecmp" => [ "$last_name", "Poo" ] ), 1 ] ),
array( "$eq" => [ array( "$strcasecmp" => [ "$middle_name", "Poo" ] ), 1 ] ),
],
),
array(
"$eq" => [
array( "$arrayElemAt" => [ array( "$slice"=> [ "$transport_details.status", -1 ] ), 0 ] ),
"Active"
]
)
]
)
)
)

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?

Mongo Query in Lithium

db.tickers.aggregate(
{ $project:
{_id: 0,
year: {$year: '$date'},
month: {$month: '$date'},
day: {$dayOfMonth: '$date'},
hour: {$hour: '$date'},
avg: '$ticker.avg'
}
},
{ $group: {
_id: { year: '$year', month: '$month', day: '$day', hour: '$hour' },
avg: { $avg: '$avg' }
}
},
{ $sort: {
'year':1, month:1, day:1, hour:1
}
}
);
How do you write the above query in Lithium?
I have tried:
$mongodb = Connections::get('default')->connection;
$tick = Tickers::connection()->connection->command(array(
'aggregate' => 'tickers',
'pipeline' => array(
'_id'=>null,
array('year' => array('$year' => '$date')),
array('month' => array('$month' => '$date')),
array('day' => array('$dayOfMonth' => '$date')),
array('hour' => array('$hour' => '$date')),
array('avg' => '$ticker.avg'),
),
array( '$group' => array( '_id' => array(
'year'=>'$year',
'month'=>'$month',
'day'=>'$day',
'hour'=>'$hour'
),
'avg' => array('$avg' => '$ticker.avg'),
),
array('$sort'=>array(
'year'=>1,
'month'=>1,
'day'=>1,
'hour'=>1
))
)
));
This is reply to the question, I had mongodb: find summary of records
The answer to the question find-summary of records, is correct, but I cannot place it in Lithium.
Thanks in advance :)
You forgot the $project level of the object. Try this instead:
$tick = Tickers::connection()->connection->command(array(
'aggregate' => 'tickers',
'pipeline' => array(
array( '$project' => array(
'_id' => 0,
'year' => array('$year' => '$date'),
'month' => array('$month' => '$date'),
'day' => array('$dayOfMonth' => '$date'),
'hour' => array('$hour' => '$date'),
'avg' => '$ticker.avg',
)),
array( '$group' => array( '_id' => array(
'year'=>'$year',
'month'=>'$month',
'day'=>'$day',
'hour'=>'$hour'
),
'avg' => array('$avg' => '$ticker.avg'),
)),
array('$sort'=>array(
'year'=>1,
'month'=>1,
'day'=>1,
'hour'=>1
))
)
));