I have numerous documents containing a field called "date" which is simply a unix timestamp.
whithin lithium, i want to find all documents in a given date range. i'm currently trying the following:
//$_stats contains two \DateTime objects which are properly initialized
$transactions = Transactions::all(
array('conditions' => array(
'tags' => array('$all' => array((string)$tag->_id)),
'date' => array('$gte' => array((int)$_stats['date_start']->getTimestamp()), '$lte' => array((int)$_stats['date_end']->getTimestamp()))
))
);
But this returns zero documents. When I remove the "date" condition, it works fine and I get all documents.
What am I missing?
Thanks, aenogym
There doesn't seem to be any need of giving an array of dates, so perhaps try:
$transactions = Transactions::all(
array('conditions' => array(
'tags' => array('$all' => array((string)$tag->_id)),
'date' => array('$gte' => (int)$_stats['date_start']->getTimestamp(), '$lte' => (int)$_stats['date_end']->getTimestamp())
))
);
Keep in mind that MongoDate stores dates as miliseconds while timestamp uses seconds. In other words MongoDate has higher precision.
Related
I have a field in my MongoDB Collection that is hosting two types of data. In some Documents that field has Integer value, e.g.
"campaign_code" : NumberLong(100097)
And in other Documents that field has Array value, e.g.
"campaign_code" : [NumberLong(100087), NumberLong(100136), NumberLong(100137), NumberLong(100138), NumberLong(100135)]
Now, previously I was grouping my result by "campaign_code", but at that time it had only Integer values. Now, the field is having two types of values. The question is is PHP MongoDB driver intelligent to perform the same functionality or do I need to change my code?
My previous PHP code:
$pipeline = array(
array('$match' => array('impression.affiliate_id' => $affiliate_id)),
array(
'$group' => array(
'_id' => array(
'impression.campaign_code' => '$impression.campaign_code'
),
'count' => array('$sum' => 1)
)
),
//sort
array('$sort' => array('count' => -1))
);
I did make some changes and added the following line of code:
array('$unwind' => '$impression.campaign_code')
But this throws an exception:
exception: Value at end of $unwind field path '$impression.campaign_code' must be an Array, but is a NumberLong64
Now the exception is quite valid because few documents have only Integer value in the field. Tell me how I can resolve this issue?
I have three working queries:
To find the rows with keyword in title field
$cursor = $collection->find(['title' => array('$regex'=>new MongoRegex($title_query))])->sort(array('timestamp'=>-1));
To find the rows with keyword in the author field
$cursor = $collection->find(['author' => array('$regex'=>new MongoRegex($author_query))])->sort(array('timestamp'=>-1));
To find the rows within a date range
$rangeQuery = array('timestamp' => array( '$gte' => $from_Id, '$lte' => $to_Id ));
$cursor = $collection->find($rangeQuery)->sort(array('timestamp'=>-1));
I want to combine the queries into 1&2, 1&3 and 2&3. However I am not able to write the correct query...
Here is my query for combining 1&2:
$cursor = $collection->find('title' => array('$regex'=>new MongoRegex($title_query)),
'author' => array('$regex'=>new MongoRegex($author_query)))->sort(array('timestamp'=>-1));
query for combining 1&3:
$rangeQuery = array('timestamp' => array( '$gte' => $from_Id, '$lte' => $to_Id ));
$cursor = $collection->find($rangeQuery, ['title' => array('$regex'=>new MongoRegex($title_query))])->sort(array('timestamp'=>-1));
Can anyone tell me how to write the correct query?
The $regex query operator should not be necessary if you are using the BSON regex type (i.e. MongoRegex in the PHP driver). Let's rewrite the original three queries:
Matching keyword in title, sorted by time descending:
$collection->find([
'title' => new MongoRegex($title_query),
])->sort(['timestamp' => -1]);
Matching keyword in author, sorted by time descending:
$collection->find([
'author' => new MongoRegex($author_query),
])->sort(['timestamp' => -1]);
Matching within a date range, sorted by time descending:
$collection->find([
'timestamp' => [
'$gte' => $from_Id,
'$lte' => $to_Id,
],
])->sort(['timestamp' => -1]);
There are several errors in the combined query examples you shared in the OP. For the "1&2" query, you were not passing an array as the first argument to find(), so that would have been a syntax error. For the "1&3" query, you're only passing the timestamp range as find() criteria, and the title regex is being incorrected passed as the second find() argument, which is reserved for specifying a project (i.e. which fields to return).
Combining the three queries is actually as easy as merging the criteria arrays. For example, we could combine all three like so:
$collection->find([
'title' => new MongoRegex($title_query),
'author' => new MongoRegex($author_query),
'timestamp' => [
'$gte' => $from_Id,
'$lte' => $to_Id,
],
])->sort(['timestamp' => -1]);
In some cases, it's not possible to merge criteria for the same field. For that reason, MongoDB has an $and query operator (see the examples for some use cases); however, in the examples above, the criteria is simple enough that you can simply combine the arrays.
I have a MongoDB aggregate in PHP defined as:
$results = $c->aggregate(array(
array(
'$project' => array(
'year' => array('$year' => array('$add' => array('$executed.getTime()', 3600))),
'month' => array('$month' => array('$add' => array('$executed.getTime()', 3600))),
'day' => array('$dayOfMonth' => array('$add' => array('$executed.getTime()', 3600)))
),
),
array(
'$group' => array(
'_id' => array('year' => '$year', 'month' => '$month', 'day' => '$day'),
'count' => array('$sum' => 1)
),
),
array(
'$sort' => array(
'_id' => 1
),
),
array(
'$limit' => 30
)
));
The problem is that the $add aggregate function in $project is not working.
exception: the $year operator does not accept an object as an operand
What is the correct way to add an arbitrary number of seconds to the date/time field $executed?
Thanks.
The issue you're seeing is a bug in MongoDB, which I've reported in SERVER-9289. A work-around for this entails wrapping the argument to the date operator in an array, as in the following shell example:
> db.foo.drop()
> db.foo.insert({x:ISODate()})
> db.foo.aggregate({$project: {x:1, y: {$year: {$add:['$x',1000]}}}})
Error: Printing Stack Trace
at printStackTrace (src/mongo/shell/utils.js:37:7)
at DBCollection.aggregate (src/mongo/shell/collection.js:897:1)
at (shell):1:8
Mon Apr 8 18:15:15.198 JavaScript execution failed: aggregate failed: {
"errmsg" : "exception: the $year operator does not accept an object as an operand",
"code" : 16021,
"ok" : 0
} at src/mongo/shell/collection.js:L898
> db.foo.aggregate({$project: {x:1, y: {$year: [{$add:['$x',1000]}]}}})
{
"result" : [
{
"_id" : ObjectId("516341333512acfb2d33f156"),
"x" : ISODate("2013-04-08T22:14:11.665Z"),
"y" : 2013
}
],
"ok" : 1
}
It should be trivial to port that over to PHP.
Having said that, your original code does have a bug in the reference to $executed. Per the $project documentation, you can refer to fields in the BSON document by name (or a dotted path to a field within objects/arrays), but there is no support for invoking JavaScript methods on those fields. Along those lines, the aggregation pipeline is operating on the raw BSON documents, so those types are never translated into their JavaScript representations over the course of the pipeline (e.g. the BSON date never becomes an ISODate).
Thankfully, calling $executed.getTime() should not even be necessary with MongoDB 2.4. SERVER-6239 improved support for BSON date handling in $add and $subtract. You can see that ticket for more details, such as the expected result for subtracting two dates, or adding a date and a number.
I am trying to sort an array in PHP by date and time which is in ISO 8601 format. I am still trying to grasp PHP and have tried many of the solutions on stack overflow and I am just not able to nail down the right function. Hopefully this is an easy answer and it will be helpful to others.
FYI, this array was generated by the Citrix API for GoToMeeting. I would like to sort the array based on startTime in the soonest time first in the list.
Here is what the array looks like using var_export with two results presented:
array (
0 => stdClass::__set_state(
array(
'createTime' => '2012-07-03T19:36:58.+0000',
'status' => 'INACTIVE',
'subject' => 'Client 1',
'startTime' => '2012-07-10T14:00:00.+0000',
'conferenceCallInfo' => 'United States: xxxxx Access Code: xxxxx',
'passwordRequired' => 'false',
'meetingType' => 'Scheduled',
'maxParticipants' => 26,
'endTime' => '2012-07-10T15:00:00.+0000',
'uniqueMeetingId' => 12345678,
'meetingid' => 123456789,
)
),
1 => stdClass::__set_state(
array(
'createTime' => '2012-07-02T21:57:48.+0000',
'status' => 'INACTIVE',
'subject' => 'Client 2',
'startTime' => '2012-07-06T19:00:00.+0000',
'conferenceCallInfo' => 'United States: xxxxx Access Code: xxxxx',
'passwordRequired' => 'false',
'meetingType' => 'Scheduled',
'maxParticipants' => 26,
'endTime' => '2012-07-06T20:00:00.+0000',
'uniqueMeetingId' => 12345678,
'meetingid' => 123456789,
)
),
)
My goal is to then output the array into html div's using a foreach loop, this code is complete and works well but my sort is off :-)
Thank you in advance for any help!
Steve
You can implement any sorting technique you can think of if you wrap it in a callback and use usort() docs here
inside your callback, you can use strtotime or similar, and do simple int comparisons.
$myDateSort = function($obj1, $obj2) {
$date1 = strtotime($obj1->startTime);
$date2 = strtotime($obj2->startTime);
return $date1 - $date2; // if date1 is earlier, this will be negative
}
usort($myArray, $myDateSort);
Long time peruser, first time question asker ...
Using PHP to query our MongoDB page visit log, I would like to get a set of records between two time periods, but exclude results that have a certain userAgent. I've figured out the time range but cannot find anywhere that explains the exclude.
Here's what I have for the query so far:
$dateRange = $collection->find(array("timeStamp" => array('$gt' => $start,
'$lt' => $end)));
Looking for code to complete the find function to exclude the records with a "userAgent" starting with "ELB"
What you're looking for is $ne or $nin, depending on whether the value you want to exclude is a single value or array of values. eg:
$dateRange = $collection->find(array("timeStamp" => array('$gt' => $start, '$lt' => end), 'userAgent' => array('$ne' => new MongoRegex('/^ELB/'))));
Documentation here:
http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24ne
http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24nin
You could append {$not: /^ELB/} to the mongo query.
Not really sure about the equivalent PHP but try something like this:
$dateRange = $collection->find(array(
'timeStamp' => array(
'$gt' => $start,
'$lt' => $end
),
'userAgent' => array(
'$not' => new MongoRegex('/^ELB/')
)
));