How to create Upcoming birthdays module in Rails?
Several answers have suggested calculating/storing day of year and sorting on that, but this alone won't do much good when you're close to the end of the year and need to consider people with birthdays in the beginning of the next year.
I'd go for a solution where you calculate the full date (year, month, day) of each person's next birthday, then sort on that. You can do this in Ruby code, or using a stored procedure in the database. The latter will be faster, but will make your app harder to migrate to a different db platform later.
It would be reasonable to update this list of upcoming birthdays once per day only, which means you can use some form of caching. Thus the speed of the query/code needed is less of an issue, and something like this should work fine as long as you cache the result:
class User
def next_birthday
year = Date.today.year
mmdd = date_of_birth.strftime('%m%d')
year += 1 if mmdd < Date.today.strftime('%m%d')
mmdd = '0301' if mmdd == '0229' && !Date.parse("#{year}0101").leap?
return Date.parse("#{year}#{mmdd}")
end
end
users = User.find(:all, :select => 'id, date_of_birth').sort_by(&:next_birthday).first(5)
Edit: Fixed to work correctly with leap years.
find upcoming birthdays from database
use this function to convert your varcher column to date format
str_to_date( fieldname, '%Y-%m-%d')
MongoDB: How to get Today, Upcoming and Past Birthdays list using MongoDB?
In the "users" collection birthday date should be stored as in below format:
"birthday" : ISODate("1975-08-26T18:30:00.000Z")
var today = new Date();
var m1 = { "$match" : { "birthday" : { "$exists" : true, "$ne" : '' } } };
var p1 = {
"$project" : {
"_id" : 0,
"username" : 1,
"birthday" : 1,
"todayDayOfYear" : { "$dayOfYear" : today },
"dayOfYear" : { "$dayOfYear" : "$birthday" }
}
};
var p2 = {
"$project" : {
"username" : 1,
"birthday" : 1,
"daysTillBirthday" : { "$subtract" : [
{ "$add" : [
"$dayOfYear",
{ "$cond" : [{"$lt":["$dayOfYear","$todayDayOfYear"]},365,0 ] }
] },
"$todayDayOfYear"
] }
}
};
if ( showcase == 'today' ) {
var m2 = { "$match" : { "daysTillBirthday" : { "$lt" : 1 } } }; // lt:1 = Today Birthdays
} else if ( showcase == 'upcoming' ) {
var m2 = { "$match" : { "daysTillBirthday" : { "$lt" : 60 } } }; // lt:60 = Next 60 days Upcoming Birthdays
} else if ( showcase == 'past' ) {
var m2 = { "$match" : { "daysTillBirthday" : { "$gt" : 60 } } }; // gt = Past 60 days Birthdays
}
db.users.aggregate([m1, p1, p2, m2]);
Rails + Mongoid + Devise : Add a birthday field to the register form
You'll need to include another module into your model class:
Mongoid::MultiParameterAttributes
Related Topics
SQL Table Aliases - Good or Bad
Running Total by Grouped Records in Table
Why Is Rand() Not Producing Random Numbers
Column Does Not Exist in the in Clause, But SQL Runs
How to Add a Column That Doesn't Allow Nulls in a Postgresql Database
Dbcc Checkident Sets Identity to 0
Using If Else in SQL Select Statement
How to Get the Last Day of Month in Postgres
How to Include Excluded Rows in Returning from Insert ... on Conflict
SQL Server Equivalent to MySQL's Explain
Return All Possible Combinations of Values Within a Single Column in SQL
Using Case Statement Inside in Clause
SQL Server Displaying Missing Dates