I'm writing a system to handle messaging.
One of the options of a user is DND (Do Not Disturb) where a user can define a time range where he should not be alerted (such as 22:00 - 08:00).
When I perform a query on users, I wish to filter out the users which currently are on DND.
In each user's document, I define a field to hold the time in seconds:
{dnd: {start: 22*3600, end: 8*3600}}
I'm not sure how to perform the query itself (the following sample will not work due to overlapping midnight)
var current; // holds current time in seconds
db.user.find({$or:[{"dnd.start":{$gt:current}},{"dnd.end":{$lt:current}}]});
A different approach to this might be to store a "blacklist" of times as an array and query that the current time is not one of those elements. It depends on how granular you need this to be. Hours or half hours may be reasonable, as far out as per minute is not too bad.
So to generate the "blacklist" per minute you could do, as JavaScript code but the principles are easy to convert:
var start = 22 * 60;
var end = 8 * 60;
var dnd = [start];
do {
start++;
if ( start == 1440 )
start = 0;
dnd.push( start );
} while ( start != end );
db.user.update({},{ "$set": { "dnd": dnd } },true)
Essentially setting the "blacklist" against the user record.
Then when you query for say 1:30 in the morning, or the 90th minute you would do:
db.user.find({ "dnd": { "$ne": 90 })
And since the "blacklist" contains that value then you do not return the user records where that value would be in the list. But for a time beyond the "dnd" range it would return:
db.user.find({ "dnd": { "$ne": 481 })
Clearly you would generally want to exclude the array element when calling up details for the user record, but that is a simple matter of projection.
Related
Is it possible to somehow do it with startAt() and endAt()?
db.ref('/items')
.orderByChild('createdAt')
.endAt(new Date().getTime() + 180 * 60 * 1000) // Updated
.on('value', () => {/* ... */})
Edit:
What I'm trying to achieve is getting all the items that are currently in the database and listening for the newly added items from the last n hours.
Using a static number like endAt(1669743560642), lets say user is there for a few minutes, the number 1669743560642 will not be updated to the new time that has gone by, it's important to somehow that value gets somehow updated in real time.
So from (user's/server time) up to n hours.
Exports from Realtime Database:
{
"items": {
"-NI3TAUjGNRlAUQ3Yc8K": {
"createdBy": "5gQ5cfGN15WCSa9RZVvAYXhKTyc2",
"createdAt": 1669743560642
},
"-NI3i-jMEyx_inQCaALr": {
"createdBy": "lc4BcHOls7cBuTVmbNo9LmtDdlf2",
"createdAt": 1669747710748
},
"-NI8-Jb_Qvd8gA3nG9cv": {
"createdBy": "5gQ5cfGN15WCSa9RZVvAYXhKTyc2",
"createdAt": 1669819620439
}
}
}
It sounds like you want to get nodes with a createdAt value of N hours ago or newer. For that I see two problems in your code:
Since Firebase Realtime Database always orders the value in ascending order, that's a startAt operation, not an endAt operation.
Since you want N hours in the past, you need to subtract from the current timestamp, not add to it.
So something like this:
db.ref('/items')
.orderByChild('createdAt')
.startAt(Date.now() - 8 * 60 * 60 * 1000) // 8 hours ago
.on('value', () => {/* ... */})
There is no way to make that startAt value dynamic though. Once you create a query, it is immutable. So if you want the window of data to move, you'll have create another query for that.
In most cases where I need this, I actually end up post-filtering the nodes in my application code. So I create the query with the startAt value as above, and then add additional logic to expire items locally too. When you have a limit on the query too, that won't work or be harder, so I try to avoid needing that combination.
I'm trying to solve an interval calendar problem.
Given busy slots as a data-set in a person's outlook calendar and
the time required for a meeting (eg: 45 mins) write a method to find
an open available slot for scheduling a meeting.
Input:
per1: (1,5) (10, 14) (19,20) (27,30)
per2: (3,5) (12,15) (18,21) (23,24)
Output: (6,9) (16,17) (22,22) (25,26)
I'm trying to see how I can solve this problem using:
A) Vanilla JavaScript (ES5 / ES6)
B) Using Data-structure like Interval trees etc.
I'm thinking maybe combine both of the calendar's and sort them in ascending order of start time and then start looking for a slot? Please correct me if I'm wrong.
Need your advice/suggestions on the same.
Given that it's a tuple of absolute hours and only two people involved, you could maintain a state array of length 24. Run a loop to mark all the hours where p1 and p2 are busy. You will be left with an array of hours where both of them will not be busy and then extract the absolute gaps between such intervals. Here is a fiddle (https://jsfiddle.net/r9nq63tk/1/) which handles the marking of the busy hours.
let freeHours = new Array(24);
// Mark the busy hours
let intervals = [];
for(let hours = 0; hours < 24; hours++) {
// Find the ranges where the hours have not been marked and push it to intervals
}
I'm running into an issue where my app is being accessed from different parts of the world. And, I have a chart to display peak access times. If accessed from a different part of the world (than the origin) I need it to reflect the converted origin time. However, the way it is currently set up, the calculation renders fooPoint.hour with the value of for example 28 instead of 00:03 (am).
I can pinpoint that this occurs in the else conditional, since, for example, if they would be Accessing from Australia, with a fooPoint.hour = 20 and this.state.timeZoneOffset = -8. 20 - (-8) = 28 and I would like it to display as 00:04. I know my calculations are wrong, so can anyone help me format this correctly please?
I failed to mention that fooPoint.hour is actually a data point I get in the foo object (which is fetched from an API), so that represents the avg. peak time of certain location. When viewed from another location in a different part of the world, I need to take into account the time zone difference to display in the chart the peak time but on their time zone
Is a library a low technical debt solution?
I have this array of objects as such:
foo: {
hour: 20
}
I obtain the timezone offset as such:
let tzOffset = new Date().getTimezoneOffset() / 60;
and store it in state
Then I have:
foo.forEach((fooPoint) => {
fooPoint.hour =
fooPoint.hour - this.state.timeZoneOffset < 0
? fooPoint.hour - this.state.timeZoneOffset + 24
: foorPoint.hour - this.state.timeZoneOffset;
});
So you have two possible conditions that you want to fix:
The timezone offset takes an early morning time and produces a negative result. I believe that your code will handle that.
The timezone offset takes a late evening result and makes it higher than 24. Your code is missing this adjustment.
Try
foo.forEach((fooPoint) => {
fooPoint.hour -= this.state.timeZoneOffset;
fooPoint.hour =
fooPoint.hour < 0
? fooPoint.hour + 24
: foorPoint.hour >= 24
? fooPoint.hour - 24
: fooPoint.hour;
});
Moving the subtraction out is just because I'm lazy and don't want to repeat it five times.
The critical part here is to test for both possibilities.
You might also find it more readable as if statements.
foo.forEach((fooPoint) => {
fooPoint.hour -= this.state.timeZoneOffset;
if (fooPoint.hour < 0) {
fooPoint.hour += 24;
} else if (fooPoint.hour >= 24) {
fooPoint.hour -= 24;
}
});
The two are functionally the same, but many would find that easier to follow.
I am asking help for a problem which I am not able to solve despite every effort. I am trying to make a counter. This counter is to be placed in a div under the available items on a webpage. This counter should be able to change its value at predefined values and intervals, for example, the value starts at 5,000 at then decreases by 1 after 2 seconds and then by 4 after next 5 seconds and then by 3 after next 2 seconds and then the process repeats (decreases by 1 after 2 seconds...) three or four sets of variation will be enough.
The value shown by the counter must not be affected by the number of page loads or simultaneous users, also it should remain if the user sees the page in two different browsers, it must only be shown as described above.
This counter must be capable of changing its value without needing the user to refresh the page.
Most straightforward solution as it appears to me would be to make the timer relative to absolute time.
This means you take the time passed since an arbitrary point in time you define as the start, e.g. right now which is var start = Date("Thu Jun 04 2015 01:46:44 GMT+0200 (CEST)") here. You can now subtract start from the current time to learn how much time has passed:
var passedSeconds = (new Date() - start) / 1000;
We divide by 1000 since JS calculates with miliseconds by default.
To update the timer, do a simple
setInterval(function() {
var passedSeconds = (new Date() - start) / 1000;
var value = doCalculationForSeconds(passedSeconds);
document.getElementById('myDisplay)'.textContent = value;
}, 1000);
which calls this method every second.
Lastly, you need to figure out a good way to calculate the progress. You could either run your formula in a big loop for all of passedSeconds. Or you evaluate if you can reduce it to a single calculation step. Will depend on the exact changes in value you'll have in your final version.
Is there a clever way to determine, say an array index, that falls within a given range? The application is similar to a playlist for a single video file with a set of from/to times that denote a "chapter".
i.e. Chapters:
00:01 - 00:30 : Call To Order
00:31 - 00:45 : Pledge of Allegence
00:46 - 02:25 : Opening Remarks
02:26 - 32:07 : Old Business
etc., etc., etc.
I have a list of these items on the page, and as the player reports where in the video it is currently playing by returning the current timestamp, I need to use jQuery to highlight the LI of the "chapter" in which the currently video timestamp falls. So if the video is currently at 1:15, that's "Opening Remarks", and the 3rd list item would be highlighted.
I've tried a number of approaches, but ultimately use PHP to write a huge series of IF/ELSEs because a playlist could have anywhere from 5 to 100 different Chapters in it and can be modified by the user at any time.
Ideally, I'd like an array using the Start time as the Key and chapter as the value, and a function that returns the first index that is >= the current timestamp. Is there any clever approach to accomplishing this? My way "works", but good God, its inefficient, running through 100 if/elses 10 times per second.
P.S. I should mention that all values are actually in seconds, with the question using H:M:S for clarity. Ultimately, I'm trying to understand how to select an array index if it falls within a given range.
Something like this:
var chapters = {
1: "callToOrder",
31: "pledgeOfAllegiance",
46: "openingRemarks",
146: "oldBusiness",
}
function currentChapter(seconds) {
var start, found = Infinity;
for (start in chapters) {
if (start <= seconds && start < found) {
found = start;
}
}
return (found === Infinity) ? null : chapters[found];
}
It will run in linear time in the number of chapters. In practice, this should be acceptable. If it isn't, then you could replace chapters with an array of objects and perform a binary search.