How to use a Mongo query in PHP? - 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'
)
);

Related

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

Multiple $group mongo request PHP

I would like to make a request with two $ group.
Here you can see the structure of my data :
{
"_id" : ObjectId("573495af4e998fec800041a7"),
"uniqid" : "not573495aeda725",
"status" : "waiting,
"date" : ISODate("2016-05-12T14:39:42.000+0000"),
"id_transaction" : null,
"hash_file" : null,
"user" : "Michel",
"desc" : "undefined",
"pharmacy" : "p56cdc980ba57f"
},
{
"_id" : ObjectId("573495af4e998fec800041a7"),
"uniqid" : "not573495aeda725",
"status" : "waiting,
"date" : ISODate("2016-05-12T14:39:42.000+0000"),
"id_transaction" : null,
"hash_file" : null,
"user" : "Julien",
"desc" : "undefined",
"pharmacy" : "p72gdf210xs68t"
}
Here is where i am in my aggregate from now :
$pipeline = array(
array(
'$project' => array(
'year' => array('$year' => array('$add' => array('$date',$offset))),
'month' => array('$month' => array('$add' => array('$date',$offset))),
'day' => array('$dayOfMonth' => array('$add' => array('$date',$offset))),
'hour' => array('$hour' => array('$add' => array('$date',$offset))),
"uniqid" => 1,
"status" => 1,
"date" => 1,
"pharmacy" => 1
)
),
array(
'$match' => array(
'$and' => array(
array(
"status" => array('$ne' => null)
),
array(
"status" => array('$ne' => "error")
),
array(
"date" => array('$lte' => new MongoDate(time()))
),
array(
"date" => array('$gt' => new MongoDate(strtotime($sixMonthAgo->format('Y-m-d'))))
)
)
)
),
array(
'$group' => array(
'_id' => array(
"month" => array('$month' => '$date'),
"year" => array('$year' => '$date'),
),
'count' => array('$sum' => 1)
)
),
array(
'$group' => array(
'_id' => array(
),
'count' => array('$sum' => 1)
)
)
);
I would like to have the number on lines where status = "waiting" grouping my request by "year/month" and by "pharmacy".
Thank you so much !
array(
'$group' => array(
'_id' => array(
"month" => array('$month' => '$date'),
"year" => array('$year' => '$date'),
"status"
),
'count' => array('$sum' => 1)
)
),
then instead of grouping - use match for _id.status ="waiting"
You do not need any $project ... Mongo Query should be -
[
{
"$match": {
"status": "waiting",
"date": {
"$gt": {
"$date": "DATE_SIX_MONTH_AGO"
},
"$lt": {
"$date": "CURRENT_DATE"
}
}
}
},
{
"$group": {
"_id": {
"month": {
"$month": "$date"
},
"year": {
"$year": "$date"
},
"pharmacy": "$pharmacy"
},
"count": {
"$sum": 1
}
}
}
]
In PHP it should be -
$pipeline = array(
array(
'$match' => array(
"status" => "waiting",
"date" => array(
'$lte' => new MongoDate(time()),
'$gt' => new MongoDate(strtotime($sixMonthAgo->format('Y-m-d')))
)
)
),
array(
'$group' => array(
'_id' => array(
"month" => array('$month' => '$date'),
"year" => array('$year' => '$date'),
"pharmacy" => '$pharmacy'
),
'count' => array('$sum' => 1)
)
)
);
I did not test in PHP, check and correct the syntax errors if any.

Convert MongoDB console aggregate to php with array

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

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!

Aggregate by country, state and city

Suppose we have a list of companies so that each company is assigned city, state (province) and country.
I'm looking for a solution, to create a 3-level aggregation as already mentioned here. Unfortunately, I am not able to translate the raw MongoDB query to PHP.
Current exception:
exception: invalid operator '$push'
Database Item:
{
"_id" : ObjectId("52c85fafc8526a4d0d21e0be"),
"city" : "Freiburg",
"country" : "DE",
"state" : "DE-BW",
"_coords" : {
"latitude" : 47.9990077,
"longitude" : 7.842104299999999
}
}
Source:
$collection = $this->getClient()->getCollection('companies');
$ops = array(
array(
'$group' => array(
'_id' => array(
'country' => '$country',
'state' => '$state',
'city' => '$city'
),
),
),
array(
'$group' => array(
'_id' => array(
'country' => '$_id.country',
'state' => '$_id.state'
),
),
),
array(
'$group' => array(
'_id' => array(
'country' => '$_id.country',
'state' => array('$push' => '$_id.state')
),
),
),
array(
'$sort' => array(
'state' => 1
),
)
);
$results = $collection->aggregate($ops);
Expected result:
[
{
"country" : "DE",
"states" :
[
{
"state" : "DE-BW",
"cities" : [
{
"city": "Freiburg",
"_coords": {
"latitude" : 47.9990077,
"longitude" : 7.842104299999999
}
},
...
]
},
...
]
},
...
]
You want two $group levels here. Optionally using $addToSet rather than $push for uniqueness:
In basic JSON notation for the rest of the people:
db.country.aggregate([
{ "$group": {
"_id": {
"country": "$country",
"state": "$state"
},
"cities": {
"$addToSet": {
"city": "$city",
"_coords": "$_coords"
}
}
}},
{ "$group": {
"_id": "$_id.country",
"states": {
"$addToSet": {
"state": "$_id.state",
"cities": "$cities"
}
}
}}
])
And in PHP notation for you:
$collection->aggregate(
array(
array(
'$group' => array(
'_id' => array(
'country' => 'country',
'state' => '$state'
),
'$cities' => array(
'$addToSet' => array(
'city' => '$city',
'_coords' => '$_coords'
)
)
)
),
array(
'$group' => array(
'_id' => '$_id.country',
'states' => array(
'$addToSet' => array(
'state' => '$_id.state',
'cities' => '$cities'
)
)
)
)
)
);
But seriously, learn how to use json_decode. JSON is pretty much the "lingua franca" for general data structure representation, not to detract from YAML or simplified XML or others. It really is not hard to translate these things into a native language representation, especially when many libraies exist to do so.

Categories