Optimizing queries on MongoDB - javascript

I have a fitness application that I am working on. I have integrated fitbit/garmin with it.
So the heart-rates data that I get from these vendors, are on a unix timestamp basis:
HEARTRATES COLLECTION
1614975688461 : 58BPM
1614975688461 : 33BPM
1614975688461 : 99BPM
1614975688461 : 44BPM
1614975688461 : 67BPM
1614975688461 : 89BPM
I have a collection in my mongoDB, which maps each of these timestamps to the heartrate.
Now I plan on having a chart which shows the weekly, monthly and the yearly average of the heart-rate for that person.
Now to do this, I can always do a less than greater query on the timestamp in my db(span of 30 days for months and span of 365 days for the yearly plot), compute and get the average on the application and show. But my doubt is, will this scale for like a million users?
Alternation solution that I have in mind: Each time the person syncs their fitbit/garmin device, I run cronjobs at the end of each day which updates collections "Weekly" and "Yearly" for each user. This way all the app has to do is query the weekly collection for the weekly data starting from the query date or the yearly collection for the data starting from the query date.
WEEKLY COLLECTION : WHICH UPDATES EVERDAY:
DAY 1: 56BPM
DAY 2: 56BPM
DAY 3: 56BPM
DAY 4: 56BPM
DAY 5: 56BPM
DAY 6: 56BPM
DAY 7: 56BPM
Does the alternate solution make any sense or is it making things worse? If you have any better solution, please let me know, thanks!

Related

JavaScript RRule - how to get "all the dates for Monday, Tuesday and Friday of 3rd week of every month for 10 counts starting from any certain date"

Hi dear stackoverflow community people, need your help in a problem.
I am using rrule JavaScript lib to generate event dates for calendar. Below is the example condition for which I want event dates.
freq: Monthly
startDate: 1 Nov 22, 6AM
count: 10
weekdays: Mon, Tuesday, and Friday
now what other inputs/parameter should I give to rrule so that it generates dates only for 3rd week of the month? (Basically, I want event to occur in every specified week (first, second, third, fourth, last) of every month in the give date range or number of counts).
please tell me if and how is it possible through rrule only or if this can be achieved using any other way or other lib along with rrule.
Thank you in advance.
Please ask if have any question or need clarity.
Initially, I tried bysetpos but then realise that it gives nth number of the day I selected (for example bysetpos:1 and byweekday: Mon will give every first monday of the month)

Advice on Filtering Availability Based on dates

I am trying to show availability for specific resorts over the course of a month. The resorts all have different rooms and different week end days based on the room. I need to be able to show valid check in days based on availability with respect to their week end days.
That probably does not make too much sense so let me elaborate. Let's assume person A wants to book a room for 3 days. In order for a check in day to be valid the room has to have continuous availability (I.E. Available 05/03, 05/06, 05/07, and 05/08 -The check in day does not count towards the three day stay). In order for the check in day to be valid it also must respect the week end day. For example Let's assume the person wants to book a 3 day stay in a one bedroom unit with a week end day of Saturday. Assuming continuous availability this would mean that valid check in days would be the following: (Saturday, Sunday, Monday, Tuesday, and Wendsday) and we would need to filter out availability on Thursday and Friday
This is where I am struggling a bit. The API endpoint that I am calling returns availability as datetime strings. I originally thought that I could just call the Date.getDay() function on the Date and then check if the week end date was greater than the day + duration of stay. However the getDay function returns 0 for Sunday, 1 for Monday, etc. so most numbers would be greater than these days. For instance if the week end day is a Sunday any number would be greater than 0 and therefore the room would show no availability.
Another option I thought of was to create a hashgraph with all the possible combination of days, but this would be a lot of work so I would like to avoid it if possible. I am hoping that there is an easy enough solution that I am not thinking of.

MySQL way to store monthly revenue

I want to store restaurant's monthly revenue (income and expenses), and later show it on a line graph for every year. I have come to this workaround I would store in year variable for example 2020-01-01 and then it should be adding values to all the following row for every month. Would it even work this way? Or should I use one date type and add months to it?
It can work, but it is not optimal.
For example if you want to see the yearly expenses you have to type every single month name into your query.
A more practical solution can be to use a single table with example columns like so:
date
is_expense (boolean)
amount (double)
restaurant_id
Where is_expense is boolean if the amount is income or expense.
You can aggregate from here everything: yearly / monthly expenses/incomes/profits etc.
You can use MySQL Functions like MONTH(date) that will give you specific month. For example if you want to aggregate all expenses for specific year & month you will do something similar to
SELECT SUM(amount) from Table WHERE is_expense=1 AND MONTH(date) = 1 AND YEAR(date) = 2020

How to store birthdays in a database with timezone support?

I am using JavaScript and a PostgreSQL database, I would like to store birthdays and notify users at 12pm in their own timezone, currently I am converting dates from their timezone to my local server time and check every hour to see if a date and time matches
import { parseFromTimeZone } from "date-fns-timezone";
const userInput = "08-11" // day/month
const timeZone = "Europe/Amsterdam"
const date = parseFromTimeZone(`2000-${userInput} 00:00:00`, { timeZone });
// This is what I store in my database
const dateToStore = date.toISOString().slice("2000:".length).split(":")[0];
// This is what I run every hour
await Birthday.find({
where: {
date: new Date().toISOString().slice("year:".length).split(":")[0],
},
});
The problem is that this solution is not very dynamic because if I migrate my server it breaks, my questions are:
How can I store the birthdays? Assume users provide the month, day and time zone
In what interval can / should I check to see if a birthday message should be sent? (00:00) in the user's time zone and specified date
What would that check look like?
I have date-fns available but I do not mind using other libraries
I'd recommend a solution with a account table containing three fields:
birthday, which is of Postgres type date.
timezone, of Postgres type text. Here you'd store something like Europe/Amsterdam, with the important part is that it's something Postgres and your date libraries can all recognize as a time zone.
last_birthday_wish_sent_at of type timestamptz (shorthand for timestamp with time zone, which stores everything internally as UTC).
I've decoupled the birthday date from its timezone because remember that a user's birthday is always the same day anywhere in the world, even if they move around. So if my birthday is August 11th in Amsterdam, it's still August 11th if I move to San Francisco. Storing these components separately would allow you to reconfigure their timezone if they move.
I'd run a cron on the 0th minute of each hour that ran logic something like this (pseudocode, sorry):
for timezone in all timezones:
if > 12 PM in timezone:
for account in accounts in timezone:
if birthday <= today AND (last_birthday_wish_sent_at IS NULL OR last_birthday_wish_sent_at < now() - '1 year):
send birthday wish
set last_birthday_wish_sent_at = now()
The purpose of last_birthday_wish_sent_at is so that you can write an algorithm that's a bit dumber and more resilient (i.e. birthday wishes still get sent even if the cron fails one hour), but still make sure to never double-send a birthday wish for any given year.
It might also be safer to model this as a separate table where you track every birthday wish you've ever sent and the user and year you sent it for. This eliminates any potential for time bugs across year boundaries.
You'd want to model the account selection and filtering in the pseudocode above as SQL so that you're not returning result sets larger than necessary. Something like:
SELECT *
FROM account
WHERE timezone IN ('Europe/Amsterdam', ...)
-- note: actual date comparison a little more complicated than this
-- because you should make sure to compare the month and day components
-- only (probably with the `EXTRACT` function)
AND birthday <= NOW()
AND (
last_birthday_wish_sent IS NULL
OR last_birthday_wish_sent < NOW() - '1 year'::interval
);
And make sure there's appropriate indexes on timezone, birthday, and last_birthday_wish_sent.
You could also tighten up the logic around time zone checks: it's always turning 12 PM somewhere, but it's perfectly predictable as to where that's happening so it's not necessary to check every time zone every time. You could also potentially push this into Postgres and get the whole selection logic packaged up into a single query.

Count items and group by a datetime unit

I'm trying to organize a query which should print a count of items ordered by a time unit such as a hour, a day etc.
My limitation is that I'm using LovefieldDB javascript library and complex queries are limited.
I have a table of Units where the main field is the date of creation like this:
2017/11/29 08:17
2017/11/29 08:47
2017/11/29 09:25
2017/11/29 11:39
The result I expect is to count per hour the number of items:
08:00 (2)
09:00 (1)
11:00 (1)
What I want to avoid is to select all rows and process them in a loop because this software is going to have thousands of rows and I'll have to create similar queries for day, month and also year.
A possible solution I thought is to add 4 more datetime fields where I would save created_hour, created_day, created_month, created_year so I can order them easly.
Do you have some tips?
This is what I mean. You can format the time to be in hours and group by the formatted time.
SELECT DATE_FORMAT(datecolumn, '%H:00'), COUNT(*)
FROM SOURCETABLE
GROUP BY DATE_FORMAT(datecolumn, '%H:00')

Categories

Resources