MongoDB using timestamps to sort - php

I have a mongodb that will be storing visitor data. I need to delete the data after ten minutes of not being active and will run a command through a cron. How would I do this?
Currently the collection is setup like so:
{ "_id" : ObjectId("4fd33e0b0feeda3b2406f6be"), "name" : "Dugley Reanimator", "updated" : "Some form of timestmap" }
How should I go about storing a timestamp that I search the collection with I.E for my MySql version:
$sql = mysql_query('DELETE FROM `visitors` WHERE NOW() > DATE_ADD(`last_seen`, INTERVAL 10 MINUTE)');

The ObjectId has a timestamp component to it. see the docs here. This essentially gives you a free insert time that you can use for sorting and querying.
The mongodb drives should give you a way to created an ObjectId off of a timestamp.
In Python:
gen_time = datetime.datetime(2010, 1, 1)
dummy_id = ObjectId.from_datetime(gen_time)
In Java:
Date d = new Date(some timestamp in ms);
ObjectId id = new ObjectId(d)
So once you've created an ObjectId based on "10 minutes ago" you can do a delete query using $lt
in the js console it would be:
db.collectionName.remove({_id: {$lt: <Your Object Id that represents 10 minutes ago>})

The best way to do it (if the timestamp is the same when you insert) its by using the _id field.
The _id field can indicate you the time, and you can do a $lte query to delete old values.
I've written about it here: http://blog.dicarsio.com/post/10739857186/quick-snippet-get-creation-time-from-id-on-mongodb

Your driver will use a MongoDate time (this may map to a more native representation in PHP).
You can then query using something like the following mongo statement:
db.myCollection.find({updated : { $lte : new ISODate("2012-06-09T16:22:50Z") } })
A rough translation for PHP would be:
$search = array(
'updated' => array(
'$lte' => new MongoDate($tenMinutesAgo))
);
$collection->find($search)
Or (Caveat: not tested):
$tenMinutesAgo = new DateTime();
$tenMinutesAgo->modify('-10 minutes');
$search = array('updated' => array('$lte' => $tenMinutesAgo));
$collection->find($search)

Related

update date to next day in laravel

I want to update my date to next day date. How Can I do it?
Now I do it using this.
$calendar = Calendar::find($id);
$calendar->update(['started_at' => $calendar->started_at->addDay(1)));
or I can do it
$calendar->started_at->addDay(1);
$calendar->save();
But this solutions is bad for me because there are 2 request in database. I wont do it using only one request.
Is there a way to dynamically update date to next day date?
For example
Calendar::where('id', $id)->updateToNextDay('started_at');
I find also sql equivalent
UPDATE `calendar` SET `started_at` = `started_at` - INTERVAL 1 DAY;
Thanks for attention.
Calendar::where('id', $id)->update() is just syntactical sugar. This proxies you to the Query Builder and is the same as running DB::table('calendar')->where('id', $id)->update();
The power of a model in an ORM is obtaining the data from the database, mapping it to properties in an object, and then manipulating that object. The overhead of a single select for an update is pretty small and if you're worried about that overhead in the development phase, you're probably overoptimizing.
If you wish to forego the select, you can use the Query Builder with a raw SQL expression. Either will call the Query Builder and run the same exact query:
Calendar::where('id', $id)
->update(['started_at' => DB::raw("started_at + INTERVAL 1 DAY")]);
or
DB::table('calendars')->where('id', $id)
->update(['started_at' => DB::raw("started_at + INTERVAL 1 DAY")]);
This should work
Calendar::where('id', $id)->update([
'started_at' => DB::raw("DATE_ADD(started_at, INTERVAL 1 DAY)")
]);
Let me know :)
$startDate = date_timestamp_get($calendar->started_at);
$date = date('Y-m-d H:i:s', strtotime('+1 day', $startDate));
$calendar->update(['started_at' => $date]);
You can write your own method in Calendar model like,
public function updateToNextDay(string $column)
{
$this->update([
$column => \Db::raw("$column + INTERVAL DAY 1");
]);
}
Not tested, but it should work.

Why doesn't this PHP MongoDB query return any results even though there is one?

I have a collection of users and users have a meta.create_date field which is an ISODate as seen below. I am trying to count how many users were created in the last N days. I have the following in the database:
{
"_id" : ObjectId("51e61fa16803fa40130a0581"),
"meta" : {
"create_date" : ISODate("2013-07-17T04:37:53.355Z")
}
}
My PHP code:
$daysAgo = new MongoDate(date('c', strtotime('-7 days')));
$query = array(
'meta.create_date' => array(
'$gte' => $daysAgo,
)
);
$result = $this->db->users->count($query);
I have also tried specifying a range using '$gte' and '$lte' where $lte => today.
However, result is coming back as 0. So what is going on here?
MongoDate() takes int time(). So, passing in a php date() to the constructor does not work. This is the proper way:
$daysAgo = new MongoDate(strtotime('-7 days'));

How to structure database and populate Calendar in CodeIgniter 2 project?

I've searched SO and Google and can't quite find what I need.
I'm building a simple Event Calendar with CodeIgniter 2. As per the CodeIgniter documentation, this is the basic code structure and it's working...
// $data[2] contains the data for day #2, etc.
$data[2] = 'event title 1';
$data[8] = 'event title 2<br/>event title 3';
$data[13] = 'event title';
$data[24] = 'event title';
// {content} in template is where $data is inserted for each day
$prefs = array (
// my calendar options
'template' => '
{cal_cell_content}{day}<br/>{content}{/cal_cell_content}
{cal_cell_content_today}<div class="highlight">{day}<br/>{content}</div>{/cal_cell_content_today}'
);
$this->load->library('calendar', $prefs);
$year = ($year === FALSE ? date('Y') : $year);
$month = ($month === FALSE ? date('m') : $month);
echo $this->calendar->generate($year, $month, $data);
Now comes how I've set up my database table...
Each Event has a title field and that creates the $slug. (~/events/view/title-slug)
Each Event has a date field and the data format is mm/dd/yyyy
Now, I'm thinking about how I'd query the database for a particular month/year and extract the data to insert into each $data[] variable.
It seems like I'll need to do the following:
create new columns in my database table for month, day, and year.
take my date input data, after it's validated, and save it into date column.
split apart my date input data, and save each piece into month, day, and year columns.
Then I would simply query my database for year & month, then loop through these results to construct my $data[] array for each day.
Is this the correct way I should be approaching this problem? It seems very redundant to have a date column as well as month, day, and year columns. Can it be done with only the date (mm/dd/yyyy) column? Too simple? Too complex? I'd like to avoid giving the user more than one field for entering a date, and ultimately I'll have a jQuery date-picker to help ensure the proper data format.
I know this may seem like a simple problem, but I've failed to locate simple code examples online. Most of the ones I've found are out of date (CI instead of CI2), too complex for what I'm doing, or use daily content items which have URI segments that already contain the date (~/events/view/yyyy/mm/dd).
EDIT:
This is how my Model is presently setup:
return $this->db->get_where('events', array('yyyy' => $year, 'mm' => $month))->result_array();
You can leave everything as-is and just structure your query to return the month and year as separate columns:
in SQL:
SELECT id,
title,
description,
MONTH(date_field) as event_month,
YEAR(date_field) as event_year
FROM my_table
... etc ...
and in Active Record (taken from here):
$this->db->select('id');
$this->db->select('title');
$this->db->select('description');
$this->db->select("MONTH(date_field) AS event_month");
$this->db->select("YEAR(date_field) AS event_year");
$query = $this->db->get('my_table');
$results = $query->result();
Firstly, I changed my date column into the MySQL "date" format, yyyy-mm-dd, in order to take advantage of the built-in MySQL date functions.
My original $query is as follows, where the 'yyyy' and 'mm' are my redundant "year" and "month" columns:
$this->db->get_where('events', array('yyyy' => $year, 'mm' => $month))->result_array();
I simply changed it into the following using the built-in MySQL date functions:
$this->db->get_where('events', array('YEAR(date)' => $year, 'MONTH(date)' => $month))->result_array();
This solved the question. Now I no longer need to maintain the extra columns for "year" and "month".
Additionally, I can assign the "day" portion of the date column to a virtual column called dd by using the MySQL "alias" function:
$this->db->select('DAY(date) AS dd');
However, this would fail since it over-rides CI's default select('*'). So you'll have to select() all the relevant columns first or it will give an error:
$this->db->select('*');
$this->db->select('DAY(date) AS dd');
And putting it all together in the Model:
// select all relevant columns
$this->db->select('*');
/* use MySQL date functions to creates virtual column called 'dd' containing
"day" portion of the real 'date' column. */
$this->db->select('DAY(date) AS dd');
/* use MySQL date functions to match $year and $month to "year" and "month"
portions of real 'date' column. */
return $this->db->get_where('events', array('YEAR(date)' => $year, 'MONTH(date)' => $month))->result_array();

PHP and MongoDate query

Created a mongo collection using a PHP script with a sub-field initialized with MongoDate. The resulting field in the collection looks like this:
"ts_add" : {
"sec" : 1335468966,
"usec" : 420000
},
When I am building my query aginst this field in PHP, I am building it like this:
$val = new MongoDate(strtotime($strDate)); // $strDate = '2012-04-25'
...
$aryQuery = array(STRING_COL_NAME => array ('$gte' => $val));
And then I do some other stuff and exec the query with the find() command.
The build query structure in PHP looks like this, according to the debugger:
find(Array
(
[ts_add] => Array
(
[$gte] => MongoDate Object
(
[sec] => 1335337200
[usec] => 0
)
)
)
In my log files, I see this:
runQuery called coll.table { ts_add: { $gte: new Date(1335337200000) } }
But no data is ever returned....and I'm kind of weirded-out by all the extra zeros but I am thinking that's default timestamp data addded or some weird MongoDate-ism...
If I manually, from the cli, run this command:
> db.table.find({ "ts_add.sec": { $gte:1335337200 } })
The full data set (as expected) is returned.
Tried this, then, from the cli to try to mimic the MongoDate thing:
> var start = new Date(2012, 3, 10)
> db.addons_add.find({ ts_add : { $gte : start } } )
No data returned.
If I use the same input data and convert it to a MongoID, searching against the $_id field, the search is successful.
Any suggestions? What am I missing? Have the feeling I'm standing three-inches from the tree complaining about how I'm not seeing the forest...
thanks!
mongod prints everything in JavaScript format, which prints dates in milliseconds (which is where all the extra 0s are coming from). So querying for 1335337200 correctly turns into 1335337200 * 1000 = 1335337200000.
The initial document fragment you pasted looks wrong, though. "ts_add" : {"sec" : 1335468966, "usec" : 420000} is JSON, but the Date type shouldn't look like that in JavaScript. How are you saving dates? It looks like they're being converted to another type of object and then stored as "generic object" instead of "date type."

Doctrine Mongodb ODM and DateTime query

I could use some help on this problem. I'm creating an application using Symfony2 + mongodb + doctrine.
I just want to use Doctrine ODM to query all the users who have been logged in the last 5 minutes. I have a User collection with a date field called date_last_login.
So I try to use the querybuilder like that:
<?php
// Creating a DateTime object and susbtract 5 min from now
// local time is 15:40:05, timezone: 'Europe/Paris'
$_dateTime = new \DateTime();
$_interval5Min = new \DateInterval('PT5M');
$_dateTime->sub($_interval5Min);
$query = $this->createQueryBuilder('User')
->field('date_last_login')->gte($_dateTime)
->getQuery();
->execute();
When I looked at the assembled query using symfony2 profiler, here is what I got:
db.User.find({ "date_last_login": { "$gte": new Date("Fri, 23 Dec 2011 15:30:05 +0100") } });
It seems fine except that the date is 10 minutes earlier rather than 5 minutes? I just don't get it. If I dump my php DateTime object, date is correct: 2011-12-23 15:35:05 (five minutes before 15:40).
So I tried to assemble the same query without substracting any minutes and this time, everything is fine:
<?php
// local time is 15:50:00
$query = $this->createQueryBuilder('User')
->field('date_last_login')->gte(new \DateTime())
->getQuery();
->execute();
// query is ok:
db.User.find({ "date_last_login": { "$gte": new Date("Fri, 23 Dec 2011 15:50:00 +0100") } });
What am I doing wrong ?
Thank you for your help!
To create query builder for get data when date_last_login great than 5 minutes there 3 ways
1) create DateTime object with your datetime format and get timestamp from DateTime object then create MongoDate object :
$timeBefore5MinutesAgo = new \DateTime(date('Y-m-d H:i:s',\time() - 5 * 60));
$mongoDateBefore5MinutesAgo = new \MongoDate($currentDateWithTime->getTimestamp());
$query = $this->createQueryBuilder('User')
->field('date_last_login')->gte($mongoDateBefore5MinutesAgo)
->getQuery();
->execute();
2) create MongoDate object and use strtotime to convert you`r datetime format to timestamp :
$mongoDateBefore5MinutesAgo = new \MongoDate(strtotime(date('Y-m-d H:i:s',\time() - 5 * 60)));
$query = $this->createQueryBuilder('User')
->field('date_last_login')->gte($mongoDateBefore5MinutesAgo)
->getQuery();
->execute();
3) only in case Doctrine 2 ODM , you can just create DateTime object with you`r datetime format:
$timeBefore5MinutesAgo = new \DateTime(date('Y-m-d H:i:s',\time() - 5 * 60));
$query = $this->createQueryBuilder('User')
->field('date_last_login')->gte($timeBefore5MinutesAgo)
->getQuery();
->execute();
all 3 ways will create query this:
db.User.find({ "date_last_login": { "$gte": new ISODate("2014-03-15T19:35:08+02:00") } });
This is likely due to this PHP bug which was fixed in 5.3.3:
https://bugs.php.net/bug.php?id=50916

Categories