Doctrine Mongodb ODM and DateTime query - php

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

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.

Laravel Carbon addHours response modification

I have a booking table where there's a bookingtime datetime field and duration field.
The duration field is integer.
In my get query for the calendar, I am showing the duration so I am trying to :
add the duration to the booking time date.
I am using this in the end of my query:
for ($i=0;$i<count($query);$i++){
$durationdate = Carbon::parse($query[$i]->bookingtime)->addHours($query[$i]->duration);
$query[$i]->end = $durationdate;
}
return $query.
The query is returning everything fine. but the "end" is returning an object
end{ date:"..." , timezone_type:3, timezon: "UTC"}
I want to modify the end to be returned like the other data in my query response as :
end : "2018-02-01 12:00:00" for example
Use the toDateTimeString() method like this:
$query[$i]->end = $durationdate->toDateTimeString();
Or the format() method:
$query[$i]->end = $durationdate->format('Y-m-d H:i:s');
The object returns is of type DateTime, so you can use the format() function to get the expect date 2018-02-01 12:00:00
$query[$i]->end = $durationdate->format('Y-m-d H:i:s');

Phalcon datetime in model query error

I am trying to execute a query like this:
Select * from table where created_at > DATE_SUB(NOW(), INTERVAL 1 DAY) in phalcon model query form. But i keep getting the following error:
Syntax error, unexpected token INTEGER(1), near to ' DAY)',
By query building is like below
$donations = Donations::query()
->where('created_at > DATE_SUB(NOW(), INTERVAL 1 DAY)')
->execute();
The above code gives me that error. Now i have tried like below
$donations = Donations::query()
->where('created_at > :holder:')
->bind(["holder" => 'DATE_SUB(NOW(), INTERVAL 1 DAY)'])
->execute();
Although this binding does not give me an error, it gives me a 0 result but i have a few rows inserted into the table to check this and when i execute the query in phpmyadmin it works correctly, So i assumed there might be a datetime mix up in the phalcon library setup of mine but when i changed from 1 DAY to 1 MONTH there is still not result. Can someone guide me on this.
INTERVAL, DATE_SUB, NOW() and other similar are MySQL only features and are not supported by PHQL.
You have two options:
1) Rewrite your WHERE condition by using PHP date:
$date = date('Y-m-d', strtotime('-1 DAY')); // Modify according to your date format
$donations = Donations::query()
->where('created_at > :holder:')
->bind(["holder" => $date)
->execute();
2) Extend MySQL with a dialect class:
$di->set('db', function() use ($config) {
return new \Phalcon\Db\Adapter\Pdo\Mysql(array(
"host" => $config->database->host,
"username" => $config->database->username,
"password" => $config->database->password,
"dbname" => $config->database->name,
"dialectClass" => '\Phalcon\Db\Dialect\MysqlExtended'
));
});
More info in the following links:
How to extend: https://forum.phalconphp.com/discussion/1748/date-sub-interval-mysql#C6291
The dialect class itself: https://github.com/phalcon/incubator/blob/master/Library/Phalcon/Db/Dialect/MysqlExtended.php

avoid time/date overlapping in mysql (laravel)

I have an iOS app where users can reserve a car either daily or hourly and if a user reserves one car other user can't reserve it till the first reservation is over. I'm using Laravel as the API to save data to MySQL database.
The format of time and date are like this 27 Dec 2016 15:21. I'm saving the data
public function requested(Request $request)
{
$time = new Reservation();
$time->from_date = $request->from_date;
$time->to_date = $request->to_date;
$time->from_time = $request->from_time;
$time->to_time = $request->to_time;
}
but this won't prevent time overlapping for sure so I tried this
$carCount = Reservation::where(
function ($query) use ($startTime, $endTime) {
$query->where('from_time', '<', $endTime)
->where('to_time', '>', $startTime);
}
)->count();
if ($carCount > 0) {
return response()->json(['request' => 'no']); // this response just to check
} else {
$carRoom->save();
response()->json(['request' => 'yes']);
}
then I thought this isn't working because of date/time format. But I wanted to make sure what format I should convert the date in laravel?
this is my migration for Reservation:
$table->string('from_date')->nullable();
$table->string('to_date')->nullable();
$table->string('from_time')->nullable();
$table->string('to_time')->nullable();
I made the string because I wasn't sure if Time or anything is the right one
My main question is how can I avoid time and date overlapping in my app's database?
Store the dates in the database as timestamps
then your query should work as intended then convert the incoming dates:
27 Dec 2016 15:21
to timestamps using strtotime() or with datetime objects
both are part of PHP check the PHP documentation to see more information.

MongoDB using timestamps to sort

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)

Categories