How do I translate a MongoDB aggregation pipeline to PHP? - 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

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

Error with dynamic json array in php

I have an application that retrieves data from a mysql database and generates a json output with php to send to a plugin.
I'm generating the following json output from php:
{
"mapwidth":"1300",
"mapheight":"1000",
"categories":"[]",
"levels":{
"id":"lots",
"title":"Lots",
"map":"maps\/lot-map.svg",
"minimap":"",
"locations":[
{
"id":"lot1",
"title":"Lot 1",
"pin":"hidden",
"description":"<p>Status: <b style=\\\"color: #8eba5e;\\\">Available<\/b><br>Size:\u00a0<b>850 sqm<\/b><br>Please get in touch for an Offer.<\/p>",
"link":null,
"x":"0.4849",
"y":"0.4629",
"fill":null,
"category":"false",
"action":"tooltip"
}
]
},
"maxscale":"1.8"
}
But the format is incorrect. Should be like the following tested json file:
{
"mapwidth": "1300",
"mapheight": "1000",
"categories": [],
"levels": [
{
"id": "lots",
"title": "Lots",
"map": "maps/lot-map.svg",
"minimap": "",
"locations": [
{
"id": "lot12",
"title": "Lot 12",
"pin": "hidden",
"description": "<p>Status: <b style=\"color: #8eba5e;\">Available</b><br>Size: <b>850 sqm</b><br>Please get in touch for an Offer.</p>",
"link": "#more",
"x": "0.3726",
"y": "0.4565"
}
]
}
],
"maxscale": 1.8
}
The difference is in the "levels" key.
This is my php code:
$results = array(
'mapwidth' => '1300',
'mapheight' => '1000',
'categories' => '[]'
);
$results['levels'] = array(
'id' => 'lots',
'title' => 'Lots',
'map' => 'maps/lot-map.svg',
'minimap' => ''
);
if ($lotes)
{
// build usable array
foreach($lotes['results'] as $lote)
{
$results['levels']['locations'][] = array(
'id' => $lote['slug'],
'title' => $lote['title'],
'pin' => $lote['pin'],
'description' => $lote['description'],
'link' => $lote['link'],
'x' => $lote['position_x'],
'y' => $lote['position_y'],
'fill' => $lote['fill'],
'category' => $lote['category'],
'action' => $lote['action']
);
}
}
else
$results['error'] = lang('core error no_results');
$results['maxscale'] = '1.8';
// display results using the JSON formatter helper
display_json($results);
Any suggestions? Thanks
You need to make the levels a multidimensional array.
$results['levels'] = array();
$results['levels'][0] = array(
'id' => 'lots',
'title' => 'Lots',
'map' => 'maps/lot-map.svg',
'minimap' => ''
);
Then when you append to do, do it as follows:
$results['levels'][0]['locations'][] = array(

mongodb php multi group stage

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?

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?

Elasticsearch Sort based on value first

I want to sort results on the release date. I want 2015 movies first and the rest of the years sorted on the has_poster value. So I get results like:
2015, 2015, 1989, 2017, 2006
etc.
So far this is what I've got.
$params['index'] = 'movies';
$params['type'] = 'movie';
$params['body']['size'] = 50;
$params['body']['sort'] = array(
array('has_poster' => "desc"),
array('_score' => "desc"),
);
$params['body']['query']['filtered'] = array(
'query' => array(
'query_string' => array(
'query' => "survivor",
'fields' => array('name', 'orig_title'),
'default_operator' => "AND"
),
)
);
I need the equivalent of ... ORDER BY FIELD(releasedate, 2015), has_poster DESC ... in MySQL for Elasticsearch.
You need a scripted sorting:
{
"sort": [
{
"_script": {
"script": "if(doc['releasedate'].date.year==2015) return 1; else return 0;",
"type": "number",
"order": "desc"
}
},
{
"has_poster": "desc"
}
]
}
Im not work =>type name is string
$params['body']['sort']= array('name' => 'desc' );
or
$params=[
'index'=>'pets',
'type'=>'bird',
'body'=>[
'query'=>[
'bool'=>[
'must'=>[],
'filter'=>[
'range'=>[
'registered'=>[
'gte' => "2020-10-01",
'lte' => "2020-11-30"]
]
]
]
],
'sort'=>[
'name'=>[
'order'=>'asc'
]
]
]
];
but not work

Categories