Convert MongoDB console aggregate to php with array - php

i am failing to convert the following mongoDB console command:
db.customers.aggregate( [
{ $group : {
_id: {
year : { $year: "$since" },
month : { $month: "$since" }
},
count: { $sum: 1 }
}
}]
);
which works into php
$customers->aggregate(array(
'$group' => array(
'_id' => array( 'year' => array('$year' => '$since'),
'month' => array('$month' => '$since')
)
),
array(
'count' => array( '$sum' => 1 )
),
)
);
which returns exception: A pipeline stage specification object must contain exactly one field.
also already tried '"$since"' with no luck

The count field must be a part of the group.
$customers->aggregate(array(
'$group' => array(
'_id' => array( 'year' => array('$year' => '$since'),
'month' => array('$month' => '$since')
),
'count' => array( '$sum' => 1 )
)
));

Related

How to use a Mongo query in PHP?

I have the following MongoDB query:
db.crimes.aggregate([
{ $match: {"CrimeLSOAName":/.*Bradford.*/} },
{
$group: {
"_id": "$CrimeType",
"count": {
$sum: 1
}
}
},
{
$sort: {
"count": -1
}
},
{
$limit: 10
}
])
Which outputs the ten most common 'CrimeTypes' where CrimeLSOAName field contains 'Bradford'. I am trying to use the query in PHP, my attempts are below but the query does not run correctly. If someone could give some help it would be appreciated.
Trying to use in PHP:
$top10Crimes = array(
array('$match') => array('CrimeLSOAName:/.*Bradford.*/'),
array(('$group') => array('_id' => '$CrimeType',
'count' => '$sum: 1')),
array('$sort') => array('count' => '-1')
array('$limit' => '10')
);
$result = $collection->aggregate($top10Crimes);
Your array is invalid, this should work. It usually helps to format your array similar to the pipeline you have in the mongo shell.
$top10Crimes = array(
array(
'$match' => array(
'CrimeLSOAName' => '.*Bradford.*/'
)
),
array(
'$group' => array(
'_id' => '$CrimeType',
'count' => array(
'$sum' => 1
)
)
),
array(
'$sort' => array(
'count' => '-1'
)
),
array(
'$limit' => '10'
)
);

How to convert mongoDB query into PHP?

My query is working in mongodb and produce output Properly. But same query i tried to run using php then it gives following error
Array
(
[ok] => 0
[errmsg] => A pipeline stage specification object must contain exactly one field.
[code] => 16435
)
Following is my MongoDB Query
db.sample_coll.aggregate(
{
$unwind: {
path:"$KeyValues",
includeArrayIndex:"arrayIndex",
preserveNullAndEmptyArrays:true
}
},
{
$project: {
timestamp:{
"$add":["$EventTS",{"$multiply":[60000,"$arrayIndex"]}]
} ,
"InputVolt":"$KeyValues.InputVolt",
arrayIndex:1
}
},
{
$match: {
$and: [
{InputVolt: {$ne: null}}
]
}
}
);
The Above query is converted in php
$pipeline = array(
array('$unwind' =>
array( 'path' => '$KeyValues'),
array( 'includeArrayIndex' => 'arrayIndex' ),
array( 'preserveNullAndEmptyArrays' => 'true' )
),
array(
'$project' => array(
'timestamp' => array(
'$add' => array(
'$EventTS',
array('$multiply' => array( 60000, '$arrayIndex' ))
)
),
array( 'InputVolt' => array( '$KeyValues', 'InputVolt' ) ) ,
array('arrayIndex' => 1)
)
),
array(
'$match' => array(
'$and' => array(
array('InputVolt' => array('$ne' => null )),
)
)
)
);
$result = $collection->aggregate($pipeline);
Kindly help to resolve this issue.
Thanks in advance
Your pipeline in PHP:
$pipeline = array(
array('$unwind' => array(
'path' => '$KeyValues',
'includeArrayIndex' => 'arrayIndex',
'preserveNullAndEmptyArrays' => true
)),
array('$project' => array(
'timestamp' => array(
'$add' => array('$EventTS', array('$multiply' => array(60000, '$arrayIndex')))
),
'InputVolt' => '$KeyValues.InputVolt',
'arrayIndex' => 1
)),
array('$match' => array(
'InputVolt' => array('$ne' => null)
))
);

Problems with converting MongoDB query using aggregate to PHP

I have the following (working) MongoDB query to generate a list of the hashtag count.
db.twitter.aggregate([
{
$group: {
_id: "$status.entities.hashtags.text",
hashtags: {
$addToSet : "$status.entities.hashtags.text"
}
}
},
{ $unwind : "$hashtags" },
{ $unwind : "$hashtags" },
{ $group : { _id : "$hashtags", count: { $sum : 1 } } },
{ $sort : { count : -1, _id : 1 } }
]);
Now I try to convert this query to PHP code (for laravel):
$cursor = DB::collection('twitter')->raw(function($collection)
{
return $collection->aggregate(array(
array(
'$group' => array(
'_id' => '$status.entities.hashtags.text',
'hashtags' => array(
'$addToSet' => '$status.entities.hashtags.text',
),
),
),
array(
'$unwind' => '$hashtags',
),
array(
'$unwind' => '$hashtags',
),
array(
'$group' => array(
'_id' => '$hashtags', '
count' => array(
'$sum => 1',
),
),
),
array(
'$sort' => array(
'count' => '-1',
'_id' => '1',
),
),
));
});
dd($cursor);
What I can derive from the Laravel-MongoDB docs is that the raw query input works the same as in PHP mongodb.
The error returned is this:
MongoResultException (15951)
localhost:27017: exception: the group aggregate field 'count' must be defined as an expression inside an object
You solved this but I can tell you where you was wrong:
'$sum => 1',
Should be:
array('$sum' => 1)
Rewrote the array and now it works:
$cursor = DB::collection('twitter')->raw(function($collection)
{
return $collection->aggregate([
[
'$group' => [
'_id' => '$status.entities.hashtags.text',
'hashtags' => [
'$addToSet' => '$status.entities.hashtags.text'
]
]
],
[ '$unwind' => '$hashtags' ],
[ '$unwind' => '$hashtags' ],
[ '$group' => [ '_id' => [ '$toLower' => '$hashtags' ], 'count' => [ '$sum' => 1 ] ] ],
[ '$sort' => [ 'count' => -1, '_id' => 1 ] ]
]);
});
Just replaced the {} by [] and the : by => and that did the trick!

mongoDB PHP aggregate collection by date and sum field per date

I am attempting to output an array of dates grouped by date with a sum of a field called minutes_numeric.
My current query is:
return $this->db->Work->aggregate(array(
array(
'$match' => array(
'date' => array('$gt' => $start, '$lt' => $end)
)
),
array(
'$project' => array(
'year' => array('$year' => '$date' ),
'month' => array('$month' => '$date' ),
'day' => array('$dayOfMonth' => '$date'),
),
),
array(
'$group' => array(
'_id' => array('year' => '$year', 'month' => '$month', 'day' => '$day'),
'minutes_numeric' => array('$sum' => 1)
),
),
array(
'$sort' => array(
'_id' => 1
),
),
array(
'$limit' => 30
)
));
Which outputs:
{
result: [
{
_id: {
year: 2013,
month: 12,
day: 4
},
minutes_numeric: 40
},
{
_id: {
year: 2013,
month: 12,
day: 11
},
minutes_numeric: 127
},
{
_id: {
year: 2013,
month: 12,
day: 12
},
minutes_numeric: 108
}
],
ok: 1
}
Which is great, however the minutes_numeric represents the number of rows for that day, so I changed the $group clause:
array(
'$group' => array(
'_id' => array('year' => '$year', 'month' => '$month', 'day' => '$day'),
'minutes_numeric' => array('$sum' => '$minutes_numeric')
),
),
Which then changes the sum (minutes_numeric) to 0 and not an actual sum.
I'm unsure why my sum is going wrong, any help is greatly appreciated
Edit,
If I update the $project to include minutes_numeric then the sum seems to exclude the $match parameters
array(
'$project' => array(
'year' => array('$year' => '$date' ),
'month' => array('$month' => '$date' ),
'day' => array('$dayOfMonth' => '$date'),
'minutes_numeric' => 1
),
),
array(
'$group' => array(
'_id' => array('year' => '$year', 'month' => '$month', 'day' => '$day'),
'minutes_numeric' => array('$sum' => '$minutes_numeric')
),
)
If this is you current query
return $this->db->Work->aggregate(array(
array(
'$match' => array(
'date' => array('$gt' => $start, '$lt' => $end)
)
),
array(
'$project' => array(
'year' => array('$year' => '$date' ),
'month' => array('$month' => '$date' ),
'day' => array('$dayOfMonth' => '$date'),
'minutes_numeric' => 1
),
),
array(
'$group' => array(
'_id' => array('year' => '$year', 'month' => '$month', 'day' => '$day'),
'minutes_numeric' => array('$sum' => '$minutes_numeric')
),
),
array(
'$sort' => array(
'_id' => 1
),
),
array(
'$limit' => 30
)
));
then the only way your $match parameters are "ignored" and the results are not as you expect is probably because they are wrong. Try checking the values of $start and $end, because the query you are using seems correct.
In case that is not the problem please update your question with the results of your current query. (Also update your query if it is different than the one in my answer)

MongoDB aggregate with PHP - group by on date

I am using an aggregate in MongoDB with PHP. The code looks like:
$results = $c->aggregate(array(
array(
'$project' => array(
'day' => array('$dayOfYear' => '$executed')
),
),
array(
'$group' => array(
'_id' => array('day' => '$day'),
'count' => array('$sum' => 1)
),
),
array(
'$sort' => array(
'_id' => 1
),
),
array(
'$limit' => 30
)
));
The problem with this, is that $dayOfYear does not sort correctly, because it sorts 2 then 3 then 345, 346... I need it to be date ascending. So, basically instead of simply doing $dayOfYear I need something like $year-$month-$dayOfMonth.
Unfortunately this does not work. Any ideas?
Thanks.
You can project those parts out and then group on them to enable you to group on the whole date:
$results = $c->aggregate(array(
array(
'$project' => array(
'year' => array('$year' => '$executed' ),
'month' => array('$month' => '$executed' ),
'day' => array('$dayOfMonth' => '$executed')
),
),
array(
'$group' => array(
'_id' => array('year' => '$year', 'month' => '$month', 'day' => '$day'),
'count' => array('$sum' => 1)
),
),
array(
'$sort' => array(
'_id.year' => 1,
'_id.month' => 1,
'_id.day' => 1
),
),
array(
'$limit' => 30
)
));
Something like that should do the trick allowing you to sort on, as you stated: $year-$month-$dayOfMonth.
You shouldn't sort on the entire _id because you've set that up to contain an object (which can sort oddly), so change your $sort to this instead to specifically sort by day of year:
'$sort' => array(
'_id.day' => 1
),

Categories