Date compare is not working in Aggregate using mongoDB and PHP - php

I have created query with date comparison in mongoDB which is working fine
but when I convert that query in PHP array and execute in aggregate method, It does not respond with any of data.
Following is mongoDB Query converted in PHP
$dateStart = new MongoDate(strtotime("2016-06-08T18:30:00.000+0000"));
$pipeline = array(
array('$match' => array(
'EventTS' => array(
'$gte' => $dateStart
)
))
);
When I pass $pipeline in aggregate
$t = $collection->aggregate($pipeline);
Sometime it respond empty records and sometime it respond with following error message
Array
(
[ok] => 0
[errmsg] => aggregation result exceeds maximum document size (16MB)
[code] => 16389
)
It seems my query is right but I am unable to identify what is the exact issue

According to above mentioned description,you just need to fetch all documents having date time greater than specific date time .
It can be accomplished easily utilizing find operation of MongoDB.
Aggregation is useful in cases where we need to perform some calculations on group of data.
Please try executing following code snippet
$date = new MongoDate(strtotime("2016-06-08T18:30:00.000+0000"));
$filter=array('EventTS'=>array('$gte'=>$date));
$data=$collection->find($filter);

Your Query is perfect but as per mongodb define your document size more than 16 MB means your single row which is greater than 16 MB.
For resolve this issue you need to use $project in aggregation that migh be solve these issue.
Eg.
$pipeline = array(
array('$match' => array(
'EventTS' => array(
'$gte' => $dateStart
)
)),
array('$project' => array('<field>'=>' <1 or true>'))
);
OR you can use FINDALL
find(array('EventTS' => array( '$gte' => $dateStart )))

Related

$slice operator of mongoDB not working in PHP

I have got this mongoDB query:
db.b_activity.find(
{token_id:"71e32267108b163ccdd3f59ba06c66674b295499"},
{activity_log:{$slice: -1}}
).pretty();
It gets all the desired results in the mongoDB terminal, but when I write the same query in PHP, it fetches the complete array every time.
MY PHP query:
$get_current_activity = $this->mongo_b_employee->b_activity->findOne(
array('token_id'=>$token_id),
array("activity_log" => array('$slice' => -1))
);
Any suggestions where I am doing something wrong?
PS: I am just trying to access the last array element.
The signature for MongoDB\Collection::findOne() is slightly different from the "shell". It requires the "projection" key in the $options as the second argument:
$get_current_activity=$this->mongo_b_employee->b_activity->findOne(
array('token_id'=>$token_id),
array(
"projection" => array( "activity_log" => array('$slice' => -1) )
)
)

How to write MongoDB query in core PHP with dynamic date variable?

I have created query in mongoDB. In MongoChef this query produces more than 10 thousand records. Now I want to execute this query in PHP. So i don't know how to write query in php with dynamic dates?
My query in mongoDB
db.PMS.aggregate(
[
{ $match: { "EventTS":{$gt:new Date("2015-01-01")}}},
]
);
Now I tried to convert in PHP with pass dynamic date variable
<?php
$mongo = new MongoClient();
$database = $mongo->securens_final;
$collection = $database->PMS;
$start_date = new MongoDate(strtotime('2015-01-01 00:00:00'));
$pipeline = [
[
'$match' => [
'EventTS' => ['$gt', $start_date]
]
]
];
$cursor = $collection->aggregate($pipeline);
echo "<pre>";
print_r($cursor);exit;
?>
After use this query i got response like this
Array
(
[waitedMS] => 0
[result] => Array
(
)
[ok] => 1
)
I don't know what is my mistake. Can any one suggest me how to slove this probelm.
Cursor does not contain any data, it fetches data as you need it (for instance as you iterate through results). If you want all the data upfront you need to use $data = iterator_to_array($cursor).

mongo sort after limit after sort - Not working

I have a collection, from which i get particular type of users using $query
Then I need sort them according to user_id ascending and limit them to 2000
From these I need the max user_id, so I sort them in descending order and limit to 1.
But this second sort forgets the limit of 2000 and sorts over over the entire cursor from find().
Any work-around?
$cursor = $collection ->find($query) // too many entries
->sort(array('user_id'=>1)) // go ascending
->limit(2000) // got our limited qouta
->sort(array('user_id'=>-1)) // go descending to get max
->limit(1); // the one with max(user_id)
Your cannot do a sort and then a limit and then a sort. The Cursor object is exactly that and it will not run the query until you iterate to the first result via getNext() which is either run manually or within a foreach loop not only that but sort is just a property of the object as such making two sorts just overwrites the property.
The best way to achieve what your looking for is:
$doc = $collection->find($query)->sort(array('user_id' => 1))
->skip(1999)->limit(1)->getNext();
That will always pick the highest user_id (which occurs at the end in this sort) of the group, which will give off the same results as doing two sorts.
How about using skip():
$cursor = $collection ->find($query)
->sort(array('user_id'=>1))
->limit(2000)
->skip(1999);
What is the reason behind sort-limit-sort-limit approach?
Can't you just do
$cursor = $collection ->find($query)
->sort(array('user_id'=>-1))
->limit(1);
EDIT: Also, only the last sort applied to the cursor has an effect. (This line is present in pymongo docs here, which makes sense.)
I am using the following code in php5 and mongodb latest build:
$doc = $collection->find($query)->sort(array('user_id' => 1))
->skip(1999)->limit(1)->getNext();
It stops working when I use ->skip(1999)->limit(1) after sort()
The cursor $doc does give me values . I tried braking it down into this:
$doc = $collection->find($query)->sort(array('user_id' => 1))
$doc = $doc->skip(1999)->limit(1);
That worked. May be you should try that in new versions.
Answer by Sammaye is correct.
You can still achieve the way you wanted. You can use aggregation framework, as it executes one stage after other stage and so on.
$doc = $collection->aggregate(array(
array(
'$match' => $query,
),
array(
'$sort' => array(
'user_id'=> 1
),
),
array(
'$limit' => 2000
),
array(
'$sort' => array(
'user_id'=> -1
),
),
array(
'$limit' => 1
),
));

Using $match to filter by dates using PHP MongoDB Aggregation Framework

I've been trying to use the PHP MongoDB driver with the aggregation framework to filter over a few dates before piping into a $group, but the match isn't doing any filtering on dates, yet it works perfectly when filtering on strings and ints.
Here's my pipeline array and code:
$date = new DateTime();
$date->sub(new DateInterval('PT' . $hours . 'H'));
$mdate = new MongoDate($date->getTimestamp());
$ops = array(
array('$match') => array(
'whenField' => array(
'$gt' => $mdate
)
)
);
$results = $this->collection->aggregate($ops);
This should return all documents in my collection where 'whenField' is in the last 3 hours, but it returns every document in my collection. I can then switch the '$gt' to an '$lt' and it also returns every document in the collection. I've put this exact same match array as a filter and used find($filter) and it correctly filters. Are Date comparisons incompatible with the aggregation framework $match or have I made some kind of error?
The $ops is wrong here, try:
$ops = array(
array('$match' => array(
'whenField' => array(
'$gt' => $mdate
)
)
);
Instead

DyanmoDB: not getting the answer I'm expecting using batch_get_item

I am trying to do a batch_get_item to request multiple items from a table. I am following the PHP example in the DynamoDB documentation, but I am not getting the results I'm expecting.
Following is the code:
$batch_array = array ();
$batch_array[]= array ('HashKeyElement' =>
array( AmazonDynamoDB::TYPE_STRING => 'V1L3M5O5L1W8R5B6D2Q1S8V0B3R8M7A6R0X0'));
$options = array (
'RequestItems' => array(
'profile_dev' => array (
'Keys' => $batch_array
)
)
);
$result = $this->db->batch_get_item($options);
Instead of getting the data, I am getting a very long response, and I'm including the relevant information from the tail end of it:
[x-aws-body] => {"RequestItems":{"profile_dev":{"Keys":[{"HashKeyElement":{"S":"V1L3M5O5L1W8R5B6D2Q1S8V0B3R8M7A6R0X0"}}]}}} ) [body] => CFSimpleXML Object ( [__type] => com.amazon.coral.validate#ValidationException [message] => One or more parameter values were invalid: The provided key size does not match with that of the schema ) [status] => 400 ) )
The hashKey for this table is a string. It has a rangeKey, but I am using the hashKey so I can get all the rows matching the hashKey. What am I missing?
The DynamoDB documentation (and SDK samples) have colossal bugs in them. The documentation, and actual SDK code, make use only of the hashKeyElement, but in fact if a table has both a hashKey AND a rangeKey, both must be used.
When I used both the hashKey and the rangeKey, the call worked.
Get (or batch get) requires you to completely define the key of all items you are getting. If you want to retrieve all rows with the same hashKey using a single call, it seems like you're looking for Query.
You don't need to use BatchGet, you should be using Query. Here is an example using the PHP SDK to get all items with the HASH key 'YourHashKey' on table 'YourTable'
// Instantiate the class
$dynamodb = new AmazonDynamoDB();
$response = $dynamodb->query(array(
'TableName' => 'YourTable',
'HashKeyValue' => array( AmazonDynamoDB::TYPE_STRING => 'YourHashKey' ),
));
Reference: http://docs.amazonwebservices.com/amazondynamodb/latest/developerguide/LowLevelPHPQuerying.html

Categories