Querying in MongoDb - ruby-on-rails

I have a model named "Class Sessions" with :scheduled_at as one of the fields, i need to extract ClassSessions whose :scheduled_at is later than a specific date.
P.S.: Scheduled_at stores date in UTC format.

Try some thing like ClassSessions.where(:scheduled_at.gte => Time.now.utc) where Time.now.utc will return the time now in utc format..
gte, lte, lt ... etc are the comparisons you're looking here. please refer to Mongoid Docs for further info.
and Rails by default combines all the condition seperated by , in where as AND so for range use that logic.
Note: Where returns a Mongoid#Criteria Object and you might have to call .results on it to return the result set.
Note2: you might've to call .to_s on Time.now.utc before passing it to mongodb where but I am not sure, try doing both if it works without to_s don't call that.
For Time you can have a look at Ruby Time Docs

Related

Getting Unix Time from Active Record ruby on rails

I have one table Bandwidth where I am saving user_traffic and created_at fields. I want to return user_name and created_at but I want date to be in Unix Time stamp in ruby on rails without using Query but by activerecord.
Bandwidth.all.select("user_traffic,created_at")
Above return both but in normal date format, but I want it to be in Unix
created_at: "2019-06-26 11:28:39", user_traffic: 0
I tried following and it works, but I could not get other column in this.
Bandwidth.find_by(id: 2).created_at.to_i
It return just timestamp which is perfect but how can I add other columns in this query. I think it is using model function to_i
=> 1561548975
If you don't need the relation later, you can use map to make any data format you want.
EX:
Bandwidth.all
.select(:user_traffic, :created_at)
.map{|b| [b.user_traffic, b.created_at.to_i]}

'Time' being changed to a 'Datetime' after being added to a hash

My controller creates something called start_time. When I print start_time's value before it's added to a LittleClassSession hash, here's what I get:
22:45:00
Okay, it looks like a value with the type time. After it's added to the hash, I ask the controller what the :start_time value is.
#little_class_session = LittleClassSession.new({
...
:start_time => start_time
})
puts #little_class_session.start_time
Here's what it puts:
2000-01-01 22:45:00 UTC
It appears to be formatted like a datetime, but asking what the .class of the start_time attribute is returns:
Time
The LittleClassSession start_time column is a time in the table (I can verify this by checking the type in the Rails console) but was a datetime when the model was created.
What could be causing this?
While your database may support a "time" column (meaning just a time with no date information), Rails by default does not (largely because neither does Ruby's standard library -- even a Time contains date information). As such, when you assign it to your model, Rails is coercing it into the type it knows how to deal with, DateTime. So, you have a few options:
Ignore the date part of the time when you use it.
Use a gem like tod to deal with your time-only types, and follow the guidelines in the README for hooking it up to Rails.
Store start_time_hour and start_time_minutes in two separate columns, and work with them as needed (e.g, Date.current + start_time_hour.hours + start_time_minutes.minutes).
Hope that helps!

How to update thousands of records

I have to update an age column based on the value in a date of birth column. There are thousands of records to update.
How do I do this using rails?
Is this the right way to do it?
User.update_all(:age => some_method);
def some_method
age = Date.today.year - dob.year
end
Yes, update_all is the right method but no, you can't do it like this. Your some_method will only get called once to set up a database call (I assume you're persisting to a database). You'll then get an error because dob won't be recognised in the scope of the User class.
You'll need to translate your date logic to SQL functions.
Something like (for mysql):
User.update_all("age = year(now()) -
year(dob) -
(DATE_FORMAT(now(), '%m%d') < DATE_FORMAT(dob, '%m%d'))")
(NB. the date_format stuff is so that you get the right age for people who's birthdays are later in the year than the current date - see this question for more details)
The other option is to use one of the batches functionality in rails.
User.where(some_condition).find_in_batches do |group_of_users|
# some logic
# e.g. group_of_users.update_all(:age => some_logic)
end
This would lock your db for less time. Note that you should pretty much always update with a condition in mind. I can't think of many cases you would want to update an entire table every time something happens.
There are a few options checkout the rails docs or the api.
your query is right.
There are many way to update record in a batch/lot.
But, I think that your query is best. Because it is rails query that will support every condition for all database.
for updating more than one attributes
Model.update_all(:column1 => value1, :column2 => value2, ........)
or
you can use :
Model.update_all("column1 = value1, column2 = value2, ........")

Rails 4 ts_range not persisting

I'm having an issue with Rails 4's support for Postgresql's ts_range data type. Here is the code that I am trying to persist:
before_validation :set_appointment
attr_accessor :starting_tsrange, :ending_tsrange
def set_appointment
self.appointment = convert_to_utc(starting_tsrange)...convert_to_utc(ending_tsrange)
end
def convert_to_utc
ActiveSupport::TimeZone.new("America/New_York").parse(time_string).utc
end
Basically I set an instance variable for the beginning and end of the appointment ts_range with two strings representing date_times. Before validation it converts them to utc and saves those values to the appointment attribute which should then be persisted. It sets things correctly but when I try to retrieve the record, the appointment attribute is now nil. Why is this code not working as expected?
Figured out the subtle bug in the code. The issue here is with the triple dot range operator. If we get two values that are the exact same time. The triple dot will say include everything from time a up until time b if they are the same exact time, then nothing will be included and the result will be nil. This can be visualized with the code below
(1...1).to_a # []
(1..1).to_a # [1]
So the way to fix this is to not use the triple dot notation when using ranges that can have the same value for a time. Use the double dot notation instead.

Dealing with column conversions in Ruby ActiveRecord

Dealing with a legacy database, I've come across a column in a SQL Server database where the date is stored as a decimal. E.g. 2011-04-23 is stored as 20110423.0.
Is there a general ActiveRecord mechanism for dealing with "weird" column storage conventions? Enum-like columns where they're actually stored as integers is another case that might also make use of the same mechanism, but I can't quite find what I'm looking for.
It seems like serialization gets me partly there:
class Thing < ActiveRecord::Base
class DecimalDate
def load(date)
if date.is_a? Numeric
y,m,d = /^(\d\d\d\d)(\d\d)(\d\d)/.match(date.to_s)[1..3].map(&:to_i)
Date.civil(y,m,d)
end
end
def dump(date)
date ? date.strftime('%Y%m%d').to_i : 0
end
end
serialize :weird_date, DecimalDate
end
rails c
> Thing.first.weird_date
=> Sun, 02 Jan 2011
But, the illusion is thin. The column doesn't "know" that it's a date stored as a decimal. E.g. comparisons fail:
rails c
> Thing.where('weird_date > ?', 1.week.ago)
...
ActiveRecord::StatementInvalid: ... Error converting data type varchar to numeric.:
If your are forced to deal with legacy data I see two possibilities to manage it.
1 From your database
You can "convert" your data by making a view of your table which convert your (date) fields on the fly. Then you make a trigger (before insert/update) on this view which convert your data back to your old format. Finally you tell ActiveRecord to use your view instead of your table.
2 From your application (Rails)
Find a way to tell ActiveRecord to do the same job. Have you already tried to manage it with AR callbacks with after_initialize and before_save? More informations here

Resources