Rrules and dayllght savings - javascript

I'm using rrule to create and store events in my database.
All was working until I found that my recurring events had an one hour difference past the 31st march.
In France, it's the day when we do a daylight saving time change.
Actually, my events are stored in a mongo database, with the start date and the duration of the event, + the eventuals rrules (all events aren't recurring events) like this :
{
"_id" : ObjectId("5c8e4706703df43859aabbe7"),
"duration" : 2879,
"type" : "unavailability",
"title" : "Weekend",
"description" : "C'est le weekend",
"rrules" : [
{
"until" : ISODate("2021-03-22T23:00:00.000Z"),
"dtstart" : ISODate("2019-03-11T23:00:00.000Z"),
"byweekday" : [
{
"weekday" : 5
},
{
"weekday" : 6
}
],
"interval" : 1,
"freq" : 2
}
],
"__v" : 0
}
When the frontend search for a date in the calendar, it will search with this args :
?from=2019-03-10T23:00:00.000Z&to=2019-03-17T23:00:00.000Z
It works well with this date, because no daylight savings are occuring in between. If I have this object :
normalizedDates = { from: 2019-03-10T23:00:00.000Z, to: 2019-03-17T23:00:00.000Z }
and this rule :
{ until: 2021-03-22T23:00:00.000Z,
dtstart: 2019-03-11T23:00:00.000Z,
byweekday: [ { weekday: 5 }, { weekday: 6 } ],
interval: 1,
freq: 2 }
Running :
const recurringDays = rruleSet.between(normalizedDates.from, normalizedDates.to)
shows, indeed :
recurringDays [ 2019-03-23T23:00:00.000Z ]
But if y use :
normalizedDates = { from: 2019-03-31T22:00:00.000Z, to: 2019-04-07T22:00:00.000Z }
Rrules returns :
recurringDays [ 2019-03-31T23:00:00.000Z, 2019-04-06T23:00:00.000Z ]
while I'm expecting :
recurringDays [ 2019-04-06T22:00:00.000Z ]
Do you know how I could handle this ?

If you want a recurrence rule to observe daylight saving time for a particular time zone, then you must schedule using this time zone. In your example, the schedule is based on UTC.
RRule provides time zone support. You should use that, and specify tzid: 'Europe/Paris'.
Also, you might consider using the toString and fromString functions to work with iCalendar formatted strings, and store that in your MongoDB instance instead of serializing the RRule as JSON.

Related

How to convert mongodb timestamps to dd-mm-yyyy format using mongoose and node.js?

Am working on a functionality where I need to display timestamps stored in mongodb in dd-mm-yyyy format. But am confused on how to write the query to get the timestamps as in required format.
Below is the sample data of dropdowns collection.
/* 1 */
{
"_id" : ObjectId("5e787e988f3b3f3a240e846e"),
"status" : true,
"company" : ObjectId("5e787e988f3b3f3a240e846d"),
"type" : "ticketstatus",
"name" : "Open",
"createdAt" : ISODate("2020-03-23T09:17:12.374Z"),
"updatedAt" : ISODate("2020-03-23T09:17:12.374Z")
}
/* 2 */
{
"_id" : ObjectId("5e787e988f3b3f3a240e846f"),
"status" : true,
"company" : ObjectId("5e787e988f3b3f3a240e846d"),
"type" : "ticketstatus",
"name" : "Closed",
"createdAt" : ISODate("2020-03-23T09:17:12.374Z"),
"updatedAt" : ISODate("2020-03-23T09:17:12.374Z")
}
/* 3 */
{
"_id" : ObjectId("5e7883ce8f3b3f3a240e8472"),
"status" : true,
"company" : ObjectId("5e787e988f3b3f3a240e846d"),
"type" : "ticketpriorities",
"name" : "High",
"createdAt" : ISODate("2020-03-23T09:39:26.167Z"),
"updatedAt" : ISODate("2020-03-23T09:39:26.167Z")
}
The query am using so far,
dropdowns.find({"company":ObjectId('5e787e988f3b3f3a240e846d')});
What would be the right approach to fetch the dates? Do I need to write a query or do I need to manipulate the returned data from the query using the lines of code? Please suggest me the best and most used way. Thanks.
You should format your dates on the client-side using a library like moment or date-fns.
For example, with date-fns:
import { format } from 'date-fns'
format(new Date(), "dd-MM-yyyy")
// 16-04-2020
date-fns is the library of choice these days because it is modular, meaning you can import only the functions you need (no affiliation). Be sure to also consider your end-user's time zone.
If you want to do it on the server-side, use $dateToString with aggregation as mentioned in the comment above:
db.collection.aggregate([
{
"$match": {
company: ObjectId("5e787e988f3b3f3a240e846d")
}
},
{
"$project": {
createdAt: {
$dateToString: {
format: "%d-%m-%Y",
date: "$createdAt"
}
},
updatedAt: {
$dateToString: {
format: "%d-%m-%Y",
date: "$updatedAt"
}
},
}
}
])
Working example here.

How to implement mongo ttl in nodejs? [duplicate]

I have a simple schema like:
{
_id: String, // auto generated
key: String, // there is a unique index on this field
timestamp: Date() // set to current time
}
Then I set the TTL index like so:
db.sess.ensureIndex( { "timestamp": 1 }, { expireAfterSeconds: 3600 } )
I expect the record to removed after 1 hour but it is never removed.
I flipped on verbose logging and I see the TTLMonitor running:
Tue Sep 10 10:42:37.081 [TTLMonitor] TTL: { timestamp: 1.0 } { timestamp: { $lt: new Date(1378823557081) } }
Tue Sep 10 10:42:37.081 [TTLMonitor] TTL deleted: 0
When I run that query myself I see all my expired records coming back:
db.sess.find({ timestamp: { $lt: new Date(1378823557081) }})
...
Any ideas? I'm stumped.
EDIT - Example document below
{ "_id" : "3971446b45e640fdb30ebb3d58663807", "key" : "6XTHYKG7XBTQE9MJH8", "timestamp" : ISODate("2013-09-09T18:54:28Z") }
Can you show us what the inserted records actually look like?
How long is "never"? Because there's a big warning:
Warning: The TTL index does not guarantee that expired data will be deleted immediately. There may be a delay between the time a document expires and the time that MongoDB removes the document from the database.
Does the timestamp field have an index already?
This was my issue:
I had the index created wrong like this:
{
"v" : 1,
"key" : {
"columnName" : 1,
"expireAfterSeconds" : 172800
},
"name" : "columnName_1_expireAfterSeconds_172800",
"ns" : "dbName.collectionName"
}
When it should have been this: (expireAfterSeconds is a top level propery)
{
"v" : 1,
"key" : {
"columnName" : 1
},
"expireAfterSeconds" : 172800,
"name" : "columnName_1_expireAfterSeconds_172800",
"ns" : "dbName.collectionName"
}

MongoDB Get highest value for each date and put them into an array

What's the best way to go about getting the highest "score" for each "date" and storing them into an array. Let's the say there are over 50 scores for any particular date.
The database looks like this
{
"_id" : ObjectId("5c06b91b583248493294"),
"classid" : "00010109e2",
"score" : 720,
"height" : 1440,
"time" : "2018-11-27T18:05:13.297621823Z",
"__v" : 0
}
And what I'm trying to do is get the highest score for each date, from a date-range of around 2 weeks and store one highest score for each date in a simple array.
I've tried loads of things, including recursion to no avail.
Can anyone shed any light on this, or point me in the right direction?
You should look into mongodb aggregation and especially $group operator, it usually used to perform such kind of operations.
In this case your code will look like that:
Scores.aggregate([
{
$match: {
time: {
$gte: startOfSomePeriod,
$lte: endOfSomePeriod
}
}
},
{
$group: {
_id: {
year: { $year: "$time" },
month: { $month: "$time" },
day: { $dayOfMonth: "$time" }
},
score: { $max: "$score" }
}
}
]);
P.S. You can use mongooses default createdAt timestamp by simply adding an option to your schema definition.

MongoDB - Query on the last object of an array?

Is there any way in MongoDB in which I can specifically query on last object's key value in an array in a single db query.
For eg: This is my doc in a collection.
{
"com" : [
{ "ts" : 1510830164203, "com" : "com1" },
{ "ts" : 1511242569673, "com" : "connected" },
{ "ts" : 1511244832741, "com" : "vb" }
],
"status" : [
{ "ts" : 1510857000000, "stat" : 3 }
]
}
So as you can see there are multiple objects in com.
How can I query on last object's ts(timestamp) or I want to check is last com inserted in between today's date or not.
I have already gone through this link. But didn't find the appropriate solution.
Any help can be appreciated.
You can use $arrayElemAt to get the last element and then match applied in aggregation. To get the last element using $arrayElemAt use second value -1 that indicate last element of an array. $arrayElemAt: ["arrayName", -1]. code will be like
db.collectionName.aggregate([
{
$project: {
status: 1,
com: {$arrayElemAt: ["$com", -1]}
}
},
{
$match: {"com.ts": 15115465465}
}
])
N.B: if you want to compare like less than or greater than then use like : $lt, $lte, $gt, or $gte any one that you need
$match: {"com.ts": {$lt: 15115465465}}
var d1 = new Date( parseInt( "Today at 12:00 AM", 16 ) * 1000 )
var d2 = new Date( parseInt( "Tomorrow at 12:00 AM", 16 ) * 1000 )
db.table.find(
{ com: { $elemMatch: {ts:{ $gte: d1, $lt: d2 } } } })
)
db.collection.aggregate(
// Pipeline
[
// Stage 1
{
$match: {
"_id" : ObjectId("5a197a3bde472b16ed9fc28d")
}
},
// Stage 2
{
$unwind: {
path : "$com"
}
},
// Stage 3
{
$sort: {
'com.ts':-1
}
},
// Stage 4
{
$limit: 1
}
]
);
You can use the below project query if you only need to find the last element.
db.collection.find({},{status: 1, com:{$slice: -1}})
More discussion on the similar topic here

MongoDB Get Document Age in Hours

I am wondering if there is a way to get a MongoDB document age in hours? Here's what I have so far, but obviously I'm using a date object, it is not calculating the hours, and it's not giving the age, just the date it was created, so it is not giving the desired result. In fact, the $divide pipeline does not even allow for date objects. Any help is appreciated. Just as an FYI, the $views variable is a NumberInt32 type and the $created_at variable is a timestamp, like: 2014-05-20T00:01:08.629Z.
db.projects.aggregate({
$project: {
"result": {
$divide: ['$views', '$created_at']
}
}
)
If you're wondering, this code is to help sort popular posts, but of course, it's only part of it. Thanks for any help!
Presuming that $views and $created_at are fields in your document containing a number of views and the created timestamp as follows:
{
"_id" : ObjectId("537abe5e8da9877dbb0ef604"),
"views" : 5,
"created_at" : ISODate("2014-05-20T00:00:00Z")
}
Then just a little date math getting the difference from the current time should do:
db.projects.aggregate([
{ "$project": {
"score": { "$divide": [
{ "$divide": [
{ "$subtract": [
new Date(),
"$created_at"
]},
100*60*60
]},
"$views"
]},
"created_at": 1,
"views": 1
}}
])
So you are basically getting the difference in hours from the current time as a date object and the created_at value. Dividing that by a standard number for hours in a day, then dividing by your views in order to get your "score" result for sorting.
When you do math operations with two date objects then the result is returned as a number. So further operations with just numbers will work from then on.

Categories

Resources