I am trying to do an aggregation using this array:
[
[
'$match' => ['deck_id' => 18],
],
[
'$project' => [
'stack' => 1,
]
],
[
'$unwind' => '$stack'
],
[
'$group' => [
'_id' => '$stack.response',
'responses' => [
'$push' => '$$ROOT.stack'
]
]
],
[
'$project' => [
'responses_count' => ['$size' => '$responses']
]
]
]
But I am getting the following exception:
Unrecognized pipeline stage name: '$unwind'
I also created an issue in GitHub with this error. I am using mongodb 4 and the latest mongodb extension from pecl.
https://github.com/mongodb/mongo-php-driver/issues/935
The following query works without error on Mongo Clients for example, but not in PHP:
db.getCollection('game_statistics').aggregate([
{$match: {deck_id: 18}},
{$project: {stack: 1}},
{$unwind: "$stack"},
{$group: {_id: "$stack.response", responses: {$push: "$$ROOT.stack"}}},
{$project: {responses_count: {'$size': "$responses"}}}
])
The problem was on my side. Even though the code was correct, there were a series of invisible UTF8 chars in the array keys or values that the driver was taking into account. Opening that file with VIM allowed me to see those characters and removing them worked.
https://jira.mongodb.org/browse/PHPLIB-396
Related
I have documents like
{
'_id': ...
'registration_temp_perm_no' => 'SIEI/216/2020',
'first_name' => 'Azra',
'last_name' => 'Ali'
},
{
'_id': ...
'registration_temp_perm_no': ....
'first_name': ...,
'last_name' : ...,
'transport_details' : [
{
...
status : "Inactive"
}
]
},
{
'_id': ...
'registration_temp_perm_no':...
'first_name' : ....
'last_name': .....,
'transport_details': []
}
Note that the documents are created/updated via front end functionalities in the following three ways
where embedded document 'transport_details' does not exist at all.
where embedded document 'transport_details' contains empty array
where embedded document 'transport_details' may contain multiple sub arrays
Now I want to fetch those documents where the status of last sub array is "Inactive" or "Requested" and where the sub array "transport_details" doesn't exist and "transport_details" is empty.
I have written query like
$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),
'$expr' => [
'$or' => [
['transport_details' => ['$exists' => false]],
['transport_details' => ['$size' => 0]],
['$eq'=> [['$arrayElemAt' => ['$transport_details.status', -1]], "Requested"]],
['$eq'=> [['$arrayElemAt' => ['$transport_details.status', -1]], "Inactive"]],
]
]
);
If we remove the lines ['transport_details' => ['$exists' => false]], ['transport_details' => ['$size' => 0]], the query is able to fetch those documents where the status of last sub array is "Inactive" or "Requested" otherwise it does not work.
When you use $expr, all next operators should have Aggregation-expressions syntax. Check full list here
You need to change
['transport_details' => ['$exists' => false]],
['transport_details' => ['$size' => 0]]
to
['$eq'=> ['$transport_details', undefined]], //equivalent to {$exists:false}
['$eq'=> [['$size' => '$transport_details'], 0]] // $size returns number, we compare numbers
If we apply $IfNull operator, we combine "no exist" + "empty array" into single condition.
Try this one:
db.collection.find({
... your extra conditions here
$expr: {
$or: [
{
$eq: [
{
$size: {
$ifNull: [
"$transport_details",
[]
]
}
},
0
]
},
{
$eq: [
{
$arrayElemAt: [
"$transport_details.status",
-1
]
},
"Requested"
]
},
{
$eq: [
{
$arrayElemAt: [
"$transport_details.status",
-1
]
},
"Inactive"
]
}
]
}
})
MongoPlayground
I have done aggregation query on student table with activity table which gives the desired fields except one field i.e "ActivityForMediumSize". This field comes empty.
The code is
$query = ["is_temp_deleted"=>0, "funRun" => "Yes"];
$pipeline = array(
array(
'$match' => $query
),
array(
'$lookup' => array(
'from' => 'studentTbl',
'localField' => '_id',
'foreignField' => 'activity_details.activityId',
'as' => 'studentsOfActivities'
)
),
['$lookup'=> [
'from'=> 'studentTbl',
'localField' => 'academic_year_Id',
'foreignField' => 'studentsOfActivities.academic_year_Id',
'as'=> 'Students'
]],
['$project' => [
'_id' => 1.0,
'activityName' => 1.0,
'activityTime' => 1.0,
'activityDate' => 1.0,
'funRun' => 1.0,
'Students' => 1.0,
'studentsOfActivities' => 1.0,
'studentsOfWeekgroup' => [
'$filter' => [
'input' => '$Students',
'as' => 'item',
'cond' => [
'$eq' => ['$$item.academic_year_Id', new MongoDB\BSON\ObjectID($this->id)],
]
]
],
'ActivityForMediumSize' => [
'$filter' => [
'input' => '$studentsOfActivities',
'as' => 'item',
'cond' => [
'$eq' =>['$$item.activity_details.-1.shirtSize', 'M'],
]
]
],
'StudentCountPerActivity'=>['$size'=>'$studentsOfActivities'],
// 'MediumCount'=>['$size'=>'$countForMedium']
]],
);
$cursor = $this->db->activitiesTbl->aggregate($pipeline)->toArray();
I have checked in console that data in "studentsOfActivities" appears like
0 =>
"_id": ObjectId("5bf518378d03ec0b2400536f"),
"ssn_Last_four": "0001",
"first_name": "Thomas",
"activity_details": [
{
"studentId": ObjectId("5bf518378d03ec0b2400536f"),
"funrun": "Yes",
"weekgroupId": ObjectId("5bf50bd48d03ec0b2400536d"),
"activityId": ObjectId("5c10a0e08d03ec1834001c6d"),
"attending": "Yes",
"id": ObjectId("5c10e5ae3250041188005dde")
},
{
"studentId": ObjectId("5bf518378d03ec0b2400536f"),
"funrun": "Yes",
"weekgroupId": ObjectId("5bf50bd48d03ec0b2400536d"),
"activityId": ObjectId("5c10a0e08d03ec1834001c6d"),
"attending": "Yes",
"shirtSize": "L",
"id": ObjectId("5c13338032500409f4007cf3")
}
]
1=>
"_id": ObjectId("5bf518378d03ec0b2400536e"),
....
....
The embedded document "activity_details" contains student's all the activities and the last element of it is considered active one i.e why I have used -1 in the above code.
Now in projection "ActivityForMediumSize" I am trying find those students who have selected shirtSize: "M". The filter on projection "ActivityForMediumSize" is not working. Please help !!!
Note that there are some students where the last activity inside "activity_details" which does not contain "shirtSize" field.
I guess "is not working" means you have an empty array. It's because you cannot refer to the last element of an array just by "-1". Instead you need to use array operators to get the last element. For example it can be a combination of arrayElemAt and slice so the filter condition can look like :
$eq: [
{ $let: {
vars: {
last: { $arrayElemAt: [
{ $slice: [ '$$item. activity_details', -1 ] },
0
] }
},
in: '$$last.shirtSize'
} },
'M'
]
It's in js syntax but it should be trivial to translate to php.
I am using mongodb 3.6 version.
I have vehicle table with documents like
{
"_id": ObjectId("5b976220d2ccda12fc0050fb"),
"VehicleNumber": "JK 678",
"NumberOfSeats": "47",
}
{
"_id": ObjectId("67976220d2ccda12fc005068"),
"VehicleNumber": "JK 779",
"NumberOfSeats": "47",
}
I have route table with data like
{
"_id": ObjectId("5b7fb426d2ccda11fc005185"),
"Name": "New Jersey City",
"VehicleDetails": [
{
"VehicleEntryId": "b8d0d2b5-8f32-6850-4d79-34ed79138d6d",
"VehicleId": ObjectId("5b976220d2ccda12fc0050fb"),
...
"Status": "Active"
},
{
"VehicleEntryId": "b8d0d2b5-8f32-6850-4d79-34ed79138568",
"VehicleId": ObjectId("67976220d2ccda12fc005068"),
...
"Status": "Active"
}
],
...
}
I have written mongodb aggregation query like
$cursor = $this->collection->aggregate([
['$match' => ["_id" => new MongoDB\BSON\ObjectID('5b7fb426d2ccda11fc005185')]],
[
'$addFields' => [
'filteredIds' => [
'$map' => [
'input' => '$VehicleDetails',
'as' => 'item',
'in' => [
'$cond' => [
['$eq' => ['$$item.Status', 'Active']],
'$$item.VehicleId',
false
]
]
]
]
]
],
array(
'$lookup' => array(
'from' => 'VehicleTbl',
'$pipeline' => [
[ '$match'=> ["_id" => ['$in' => ['$$filteredIds'] ]]],
],
'as' => 'AllotedVehicleDetails'
)
),
])->toArray();
Basically I am trying to fetch all assigned vehicle to a particular route. So I first fetch all the actively alloted vehicle ids by using $addFeilds operator and putting them in "filteredIds" then in lookup I am trying to fetch vehicle informations from vehicle table using pipeline. The above code throws error message 'Uncaught exception 'MongoDB\Driver\Exception\RuntimeException' with message '$lookup argument '$pipeline: [ { $match: { _id: { $in: [ "$$filteredIds" ] } } } ]' must be a string, is type array' in' line no 32.
Please help!!!
use pipeline instead of $pipeline.
Example:
{
$lookup : {
'from' : 'vehicles',
let : { localFilterIds : '$filteredIds'},
pipeline : [
{'$match' : { $expr: { '$in' : [ '$_id', '$$localFilterIds' ] }} }
],
'as' : 'AllotedVehicleDetails'
}
}
Note: This is tested in mongoDb GUI Robo 3T.
I wrote a aggregate query to get data in mongodb. same query I need to run via php codigniter,
This is my mongodb query
db.states.aggregate([
{
$project: {
states: {
$filter: {
input: "$states",
as: "state",
cond: { $eq: [ "$$state.country_id", "101" ] }
}
}
}
}
])
same query i need to convert for php codignater. I have used this library to perform the db operarion.
I tried:
$pipeline = [
[
'$project' => [
'states' =>[
'$filter' => [
'input' => '$states',
'as' => 'state',
'cond' => [
'$eq' => [
'$$state.country_id' => $country_id
]
]
]
]
]
]
];
$result = $this->mongo_db2->aggregate('tb10_states', $pipeline);
But, its throw Message: Unrecognized expression '$$state.country_id'
Suggest me How to fix this.
Right now, I have the below code in my laravel app. I'm running into this error: mongo1:27017: exception: aggregation result exceeds maximum document size (16MB). I read that I should use mapReduce instead of aggregate to avoid this issue but am unsure how to translate the below to mapReduce using Laravel MongoDB by jenssegers.
Here is my code using aggregate:
$email_duplicates = User::raw(function ($collection) {
return $collection->aggregate(
[
[
'$group' => [
'_id' => [
'email' => '$email',
],
'uniqueIds' => [
'$addToSet' => '$_id',
],
'count' => [
'$sum' => 1,
],
],
],
[
'$match' => [
'count' => [
'$gt' => 1,
],
],
],
],
[
'allowDiskUse' => true,
]
);
});
Can anyone help?