I have a collection with an index on :created_at (which in this particular case should be a date)
From rails what is the proper way to save an entry and then retrieve it by the date?
I'm trying something like:
Model:
field :created_at, :type => Time
script:
Col.create(:created_at => Time.parse(another_model.created_at).to_s
and
Col.find(:all, :conditions => { :created_at => Time.parse(same thing) })
and it's not returning anything
The Mongo driver and various ORMs handle Date, Time and DateTime objects just fine; there's no reason to cast them to strings.
Col.create(:created_at => another_model.created_at)
And finding:
Col.all(:created_at => another_model.created_at)
You don't want to be setting strings, because dates are stored internally as BSON Date objects, and are indexed and searched as such. If you save them as strings, you won't be able to do things like greater than/less than/range comparisons effectively.
Col.create(:created_at => Time.parse(another_model.created_at).to_s)
That line would pass your time object as a String, take off the to_s to send it to the type parsing layer in your ORM (MongoMapper or Mongoid) as a Time object. That's the only error I can see that would cause it to not work.
Related
I've got below value in my hstore column widget_locations:
"left_area2"=>"{\"youtube\"=>{:youtube_id=>\"aasdsadsa\", :from=>\"100\", :to=>\"200\"}}"
This is saved using:
#webcast.create(:widget_locations => {:left_area2 => {:youtube => {:youtube_id => "aasdsadsa", :from => "100", :to => "200"}}})
I tried retrieving by
#webcast.left_area2
this is now returning
"{\"youtube\"=>{:youtube_id=>\"aasdsadsa\", :from=>\"100\", :to=>\"200\"}}"
Is there a way to change this into Rails array?
Without seeing your Webcast model, I'm guessing that you haven't used serialize on widget_locations as an hstore column should return a Hash.
Add serialize :widget_locations, ActiveRecord::Coders::Hstore to the top of your model and restart your server - that should at least return an object (e.g. Hash) rather than a string.
This should be an easy one, but I've googled a fair bit.
I am trying to create a database log for my rails app. The log is a postgres table which has a timestamp field, which I have given a DEFAULT of current_timestamp. This works perfectly in raw SQL, if I leave the timestamp field out of my INSERT query, it gets the current timestamp correctly.
In rails I have;
entry = LogTable.new :fieldA => 'valA', :fieldB => 'valB'
entry.save
(LogTable extends ActiveRecord::Base)
Which results in an INSERT query that contains all fields, including the timestamp field set to NULL, which is not allowed by the database so it errors.
I have tried setting :timestamp => 'current_timestamp' and :timestamp => 'DEFAULT' but all end up trying to set it to NULL.
Is your current_timestamp just the current date/time? If so, you can stay simple and do something like:
entry = LogTable.new :fieldA => 'valA', :fieldB => 'valB', :timestamp => Time.now
If it's something more complex and you really want to use DB-side defaults, this page might help: http://drawohara.com/post/6677354/rails-activerecord-default-values.
I'm working on creating a Rails app that allows users to set availability Sunday through Saturday, with a start time, end time, and location (simple string). I have an User object and I'm unsure of how to continue. I know I could have a large set of Time objects like so:
class User
field :mondayStartTime, :type => Time
field :mondayEndTime, :type => Time
field :mondayLocation, :type => String
field :tuesdayStartTime, :type => Time
field :tuesdayEndTime, :type => Time
field :tuesdayLocation, :type => String
...
field :sundayEndTime, :type => Time
field :sundayLocation, :type => String
end
However, this seems terribly inefficient, though creating another unique object class seems just as bad and only results in more lines of code. Is there an easier way of implementing start/end times for a Sunday through Saturday schedule?
Thanks!
At first glance, I'd create an "Availability" model/class (or something less prone to misspelling like "Schedule") with the attributes of start_at, end_at, location, and day_of_week - and have that class belong to the User (and with the User having a "has_many :availabilities" or "has_many :schedules"). That seems (again at first glance) to be the most efficient and easiest to get the data back out - and you can use that separate class to do things like grouping schedules/availabilities together more easily.
Have you thought about creating objects for each day of the week, that have a start, end and location property?
Or perhaps, a Jobs object(model) that has fields for start time, end time, and location.
This way it would be possible to do, has_many :jobs and then you can either narrow down, by day, or select by a particular day. The narrowing down should be feasible with the ruby Time Class or ActiveSupport class (3.days.from_now, etc).
irb(main):001:0> require 'active_support/all'
=> true
irb(main):002:0> 2.days.ago
=> 2012-04-03 08:30:31 -0700
irb(main):003:0> 2.days.from_now
=> 2012-04-07 08:33:01 -0700
EDITED TO SHOW ACTIVE SUPPORT TIME CLASS
I am using rails 3 with mongoid.
I have a collection of Stocks with an embedded collection of Prices :
class Stock
include Mongoid::Document
field :name, :type => String
field :code, :type => Integer
embeds_many :prices
class Price
include Mongoid::Document
field :date, :type => DateTime
field :value, :type => Float
embedded_in :stock, :inverse_of => :prices
I would like to get the stocks whose the minimum price since a given date is lower than a given price p, and then be able to sort the prices for each stock.
But it looks like Mongodb does not allow to do it.
Because this will not work:
#stocks = Stock.Where(:prices.value.lt => p)
Also, it seems that mongoDB can not sort embedded objects.
So, is there an alternative in order to accomplish this task ?
Maybe i should put everything in one collection so that i could easily run the following query:
#stocks = Stock.Where(:prices.lt => p)
But i really want to get results grouped by stock names after my query (distinct stocks with an array of ordered prices for example). I have heard about map/reduce with the group function but i am not sure how to use it correctly with Mongoid.
http://www.mongodb.org/display/DOCS/Aggregation
The equivalent in SQL would be something like this:
SELECT name, code, min(price) from Stock WHERE price<p GROUP BY name, code
Thanks for your help.
MongoDB / Mongoid do allow you to do this. Your example will work, the syntax is just incorrect.
#stocks = Stock.Where(:prices.value.lt => p) #does not work
#stocks = Stock.where('prices.value' => {'$lt' => p}) #this should work
And, it's still chainable so you can order by name as well:
#stocks = Stock.where('prices.value' => {'$lt' => p}).asc(:name)
Hope this helps.
I've had a similar problem... here's what I suggest:
scope :price_min, lambda { |price_min| price_min.nil? ? {} : where("price.value" => { '$lte' => price_min.to_f }) }
Place this scope in the parent model. This will enable you to make queries like:
Stock.price_min(1000).count
Note that my scope only works when you actually insert some data there. This is very handy if you're building complex queries with Mongoid.
Good luck!
Very best,
Ruy
MongoDB does allow querying of embedded documents, http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ValueinanEmbeddedObject
What you're missing is a scope on the Price model, something like this:
scope :greater_than, lambda {|value| { :where => {:value.gt => value} } }
This will let you pass in any value you want and return a Mongoid collection of prices with the value greater than what you passed in. It'll be an unsorted collection, so you'll have to sort it in Ruby.
prices.sort {|a,b| a.value <=> b.value}.each {|price| puts price.value}
Mongoid does have a map_reduce method to which you pass two string variables containing the Javascript functions to execute map/reduce, and this would probably be the best way of doing what you need, but the code above will work for now.
I would like to know if it is possible to get the types (as known by AR - eg in the migration script and database) programmatically (I know the data exists in there somewhere).
For example, I can deal with all the attribute names:
ar.attribute_names.each { |name| puts name }
.attributes just returns a mapping of the names to their current values (eg no type info if the field isn't set).
Some places I have seen it with the type information:
in script/console, type the name of an AR entity:
>> Driver
=> Driver(id: integer, name: string, created_at: datetime, updated_at: datetime)
So clearly it knows the types. Also, there is .column_for_attribute, which takes an attr name and returns a column object - which has the type buried in the underlying database column object, but it doesn't appear to be a clean way to get it.
I would also be interested in if there is a way that is friendly for the new "ActiveModel" that is coming (rails3) and is decoupled from database specifics (but perhaps type info will not be part of it, I can't seem to find out if it is).
Thanks.
In Rails 3, for your model "Driver", you want Driver.columns_hash.
Driver.columns_hash["name"].type #returns :string
If you want to iterate through them, you'd do something like this:
Driver.columns_hash.each {|k,v| puts "#{k} => #{v.type}"}
which will output the following:
id => integer
name => string
created_at => datetime
updated_at => datetime
In Rails 5, you can do this independently of the Database. That's important if you use the new Attributes API to define (additional) attributes.
Getting all attributes from a model class:
pry> User.attribute_names
=> ["id",
"firstname",
"lastname",
"created_at",
"updated_at",
"email",...
Getting the type:
pry> User.type_for_attribute('email')
=> #<ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::MysqlString:0x007ffbab107698
#limit=255,
#precision=nil,
#scale=nil>
That's sometimes more information than needed. There's a convenience function that maps all these types down to a core set (:integer, :string etc.)
> User.type_for_attribute('email').type
=> :string
You can also get all that data in one call with attribute_types which returns a 'name': type hash.
You can access the types of the columns by doing this:
#script/console
Driver.columns.each {|c| puts c.type}
If you want to get a list of all column types in a particular Model, you could do:
Driver.columns.map(&:type) #gets them all
Driver.columns.map(&:type).uniq #gets the unique ones
In rails 5 this will give you a list of all field names along with their data type:
Model_Name.attribute_names.each do |k| puts "#{k} = #{Model_Name.type_for_attribute(k).type}" end
Rails 5+ (works with virtual attributes as well):
Model.attribute_types['some_attribute'].type
This snippet will give you all the attributes of a model with the associated database data types in a hash. Just replace Post with your Active Record Model.
Post.attribute_names.map {|n| [n.to_sym,Post.type_for_attribute(n).type]}.to_h
Will return a hash like this.
=> {:id=>:integer, :title=>:string, :body=>:text, :created_at=>:datetime, :updated_at=>:datetime, :topic_id=>:integer, :user_id=>:integer}
Assuming Foobar is your Active Record model. You can also do:
attributes = Foobar.attribute_names.each_with_object({}) do |attribute_name, hash|
hash[attribute_name.to_sym] = Foobar.type_for_attribute(attribute_name).type
end
Works on Rails 4 too
In Rails 4 You would use Model.column_types.