mongodb php multi group stage - php

I want to execute below mongodb script using php:
db.getCollection('play_history').aggregate(
[ { $match : { At : {$gte : 1470307490, $lt : 1470307497649}, moneyType:1 } } ,
{
$group:
{
_id: { gameType: "$gameType", sessionId: "$sessionId"},
}
},
{
$group:
{
_id: "$_id.gameType",
count: { $sum: 1}
}
}
])
Below is the php snip code:
$match = [ 'moneyType' => 1,
'At' => ['$gt' => 12, '$lt' => 1470307497649]];
$command = new MongoDB\Driver\Command([
'aggregate' => 'play_history',
'pipeline' => [
['$match' => $match],
['$group' =>
['_id' => ["gameType" => '$gameType', "sessionId" => '$sessionId']]],
['$group' =>
['_id' => '$_id.gameType' ],
'countGame' => ['$sum' => 1 ]],
],
'cursor' => new stdClass,
]);
$cursor = $manager->executeCommand('falcon', $command);
The above code give me the following error:
A pipeline stage specification object must contain exactly one field
I have tried to change several grouping orders but it didn't work. Is that a limitation of PHP to just has only one group stage per command?

Related

Sum all specified fields in a collection

I am using PHP to access a MongoDB collection in which I have recorded purchases of my shop.
Example document:
{"_id":{"$oid":"61ff011a5b55479726fe5208"},"monthYear":"2-2022","timestamp":{"$date":"2022-02-05T22:58:34.952Z"},"productIndex":"x","productPriceUSD":10,"customerName":"x","customerID":"x","notes":"x","__v":0}
Now I want to add the value of field "productPriceUSD" from all documents in the collection and get a sum at the end.
Maybe someone can help me?
That's my start:
I know, it probably does not make any sense.
$client = new MongoDB\Client(
'xxx'
);
$sumtotal = function() use ($client)
{
$collection = $client->database->purchases;
$options = [];
$filter = [
['$group' => [
'_id' => '$_id',
'productPriceUSD' => [
'$sum' => [
'$cond' => [ [ '$gt' => [ '$productPriceUSD', 0 ] ], '$productPriceUSD', 0 ],
],
]],
]];
$result = $collection->aggregate($filter, $options);
};
Here two pipelines you need
{
$group: {
_id: "",
total: { $sum: "$productPriceUSD" }
}
},
{
$project: {
_id: 0,
total: "$total"
}
}
Playground link: https://mongoplayground.net/p/8OTGkK7wLIp

Convert Mongodb shell query with map and aggregate to php

I wrote a mongodb query that I am having a hard time converting to php code:
var geoips = db.geoip.find().map(function(like){ return like.ip; });
var result = db.audit.aggregate([
{ $match: { ip: { $nin: geoips } } },
{ $group: {
_id: "$ip",
count: { $sum: 1 }
}}
]);
UPDATE:
The above query is the equivalent of the following Relation Database Query
Select ip,count(*)
from audit
where ip not in (select ip from geoip)
group by ip
Since I had to make this query in mongodb version 3.0, I was unable to take advantage of $lookup as suggested in an answer.
The below PHP code accomplishes the above objective and works as expected. It gets the distinct ips from geoip collection. It passes that result and does an aggregate on the audit collection to get the desired result.
$geoipcolln = $this->dbConn->selectCollection('geoip');
$geoips = $geoipcolln->distinct('ip');
$match = array('ip' => array('$nin' => $geoips));
$result = $this->collection->aggregate(
array(
'$match' => $match
),
array('$group' => array(
'_id' => '$ip',
'count' => array('$sum' => 1.0),
))
);
This can be done in one aggregation query using the $lookup operator as follows:
var result = db.audit.aggregate([
{
"$lookup": {
"from": "geoip",
"localField": "ip",
"foreignField": "ip",
"as": "geoips"
}
},
{ "$match": { "geoips.0": { "$exists": false } } },
{ "$group": {
"_id": "$ip",
"count": { "$sum": 1 }
}}
])
which can then be translated to PHP as:
<?php
$m = new MongoClient("localhost");
$c = $m->selectDB("yourDB")->selectCollection("audit");
$ops = array(
array(
"$lookup" => array(
"from" => "geoip",
"localField" => "ip",
"foreignField" => "ip",
"as" => "geoips"
)
),
array( "$match" => array( "geoips.0" => array( "$exists" => false ) ) ),
array( "$group" => array(
"_id" => "$ip",
"count" => array( "$sum" => 1 )
))
);
$results = $c->aggregate($ops);
var_dump($results);
?>

Shanty Mongo aggregate $multiply

How to get percentages between desktop and mobile from a group pipeline in a MongoDB aggregate.
Sample data:
{
_id : 1,
full_url : 'www.example.com/blog/about',
access_time : ISODate("2015-12-21T14:50:19Z")
},
{
_id : 2,
full_url : 'www.example.com/blog/statistic',
access_time : ISODate("2015-12-21T14:50:22Z")
},
{
_id : 3,
full_url : 'm.example.com/detail/article1',
access_time : ISODate("2015-12-21T14:50:41Z")
}
Result should look like this:
{
_id : 'www.example.com',
percentage : 28
},
{
_id : 'm.example.com',
percentage : 72
}
Shanty Mongo
class App_Model_Mongodb_RequestLog extends Shanty_Mongo_Document
{
protected static $_db = 'sam';
protected static $_collection = 'requestlog';
public static function device()
{
$total = self::all()->count();
$pipeline = [
[
'$match' => [
'access_time' => [
'$gte' => new \MongoDate( strtotime('-1 minute') ),
'$lte' => new \MongoDate(),
],
'$and' => [
['full_url' => new \MongoRegex("/www.example.com/i")],
['full_url' => new \MongoRegex("/m.example.com/i")],
]
]
],
[
'$group' => [
'_id' => '$full_url',
'count' => ['$sum' => 1]
]
],
[
'$project' => [
'percentage' => [
'$multiply' => [
'$count', 100 / $total
]
]
]
],
[
'$sort' => ['percentage' => -1]
]
];
return self::getMongoCollection()->aggregate($pipeline);
}
}
But I've no idea how to do that. I've tried $divide and other things, but without success. any suggestions?

MongoDB PHP Aggregation empty results with date ($lte, $gte) in $match

I've the following Aggregation:
$pipeline = array(
array('$match' => array(
'matchDate' => array(
'$lte' => $dateEnd, // DateTime object
'$gte' => $dateStart // DateTime object
)
)),
array('$group' => array(
'_id' => '$sport',
'count' => array('$sum' => 1)
))
);
$m = new \MongoClient('localhost');
$c = $m->selectDB('test_database')->selectCollection('Match');
$t = $c->aggregate($pipeline);
This aggregation will return an empty Result.
If I run the aggregation on my MongoDB directly, it works without problems and gives the expected results.
Here is the native query.
db.Match.runCommand({
"aggregate": "Match",
"pipeline": [
{
"$match": {
"matchDate": {
"$lte": new ISODate("2015-10-07T23:59:59+02:00"),
"$gte": new ISODate("2015-10-06T00:00:00+02:00")
}
}
},
{
"$group": { "_id": "$sport", "count": { "$sum": 1 } }
}
]});
The problem occurs only with aggregation. Find queries with date ($lte, $gte) works also without problems.
Here is an example document.
{
"_id": ObjectId("5613bbb79042ad801f0041ab"),
"sport": ObjectId("5613bbb79042ad801f0041a8"),
"matchDate": new Date("2015-09-26T13:45:00+0200")
}
Has someone an idea whats happen here?
I'm Using
MongoDB Support 1.6.11
PHP 5.6.13
MongoDB 3.0.6
It'll work with MongoDate.
$pipeline = array(
array('$match' => array(
'matchDate' => array(
'$lte' => new MongoDate($dateEnd->getTimestamp()),
'$gte' => new MongoDate($dateStart->getTimestamp())
)
)),
array('$group' => array(
'_id' => '$sport',
'count' => array('$sum' => 1)
))
);
$m = new \MongoClient('localhost');
$c = $m->selectDB('test_database')->selectCollection('Match');
$t = $c->aggregate($pipeline);
Thanks #Blakes Seven

How do I translate a MongoDB aggregation pipeline to PHP?

I am using the following MongoDB query (and it's working with RoboMongo), returning an array with 30 elements, one for each day of the date range specified on $match element:
db.alcobaca.aggregate( [
{ $project:
{ time:1,
temp:1,
frio:
{
$cond:
[{ $lte: [ "$temp", 7.2 ] }, 0.25, 0 ]}}},
{
$match: {
time: {
$gte: new Date('11/01/2011'),
$lt: new Date('11/30/2011')
}
}
},
{
$group: {
_id: {
ord_date: {
day: {$dayOfMonth: "$time"},
month: {$month: "$time"},
year: {$year: "$time"}
}
},
horasFrio: { $sum: '$frio' }
}
},
{ $sort: { '_id.ord_date': 1} }
])
When I translate to PHP, working on the Laravel framework, after a successful connection to the database (I have already tested it with another, simpler query):
$c->aggregate (
[
['$project' =>
['time' => 1,
'temp' => 1,
'frio' =>
['$cond' =>
[['$lte' => ['$temp', 7.2]], 0.25, 0]]]],
['$match' => [
'time' => [
'$gte' => new DateTime('11/01/2011'),
'$lt' => new DateTime('11/03/2011')
]
]
],
[
'$group' => [
'_id' => [
'ord_date' => [
'day' => ['$dayOfMonth' => '$time'],
'month' => ['$month' => '$time'],
'year' => ['$year' => '$time']
]
],
'horasFrio' => ['$sum' => '$frio']
]
],
['$sort' => ['_id.ord_date' => 1]]
]
);
It returns an empty array. Am I missing some syntax issue?
Thank you

Categories