I have an Activity_Part model with a field called activity_json. this field is a hash that has a key named "image". I want to query/select only the ID of all Activity_Part only with activity_json field with key "image"
ActivityPart < ApplicationRecord {
:id => :integer,
:owner_id => :integer,
:activity_type => :string,
:activity_json => :json,
I thought of doing something like this:
x = ActivityPart.all
x.pluck(activity_json: 'image')
but I don't know how to return just the Activity ID with all the images in the activty_json field
I'll assume that you're using postgres.
jsonb type has the ? operator which can be used like this: ActivityPart.where("activity_json ? 'image'") as per documentation.
If your column is of a json type then consider changing it to jsonb. You can alternatively cast it to jsonb in the query like so: ActivityPart.where("activity_json::jsonb ? 'image'") but be aware that this might negatively affect the performance of the query.
Related
I have a column car_details with 2000 entries, each of which is a hash of info that looks like this:
{"capacity"=>"0",
"wheels"=>"6",
"weight"=>"3000",
"engine_type"=>"Diesel",
"horsepower"=>"350",
"fuel_capacity"=>"35",
"fuel_consumption"=>"30"}
Some cars have more details, some have less. I want to rename the "fuel_consumption" key to "mpg" on every car that has that key.
Well, a previous answer will generate 2000 requests, but you can use the REPLACE function instead. Both MySQL and PostgreSQL have that, so it will be like:
Car.update_all("car_details = REPLACE(car_details, 'fuel_consumption', 'mpg')")
Take a look at the update_all method for the conditions.
See also PostgreSQL string functions and MySQL string functions.
Answer posted by #Ivan Shamatov works very well and is particular important to have good performances on huge databases.
I tried it with a PostgreSQL database, on a jsonb column.
To let it works we have to pay same attention to data type casting.
For example on a User model like this:
User < ActiveRecord::Base {
:id => :integer,
:created_at => :datetime,
:updated_at => :datetime,
:email => :string,
:first_name => :string,
:last_name => :string,
:custom_data => :jsonb
}
My goal was to rename a key, inside custom_data jsonb field.
For example custom_data hash content from:
{
"foo" => "bar",
"date" => "1980-07-10"
}
to:
{
"new_foo" => "bar",
"date" => "1980-07-10"
}
For all users records present into my db.
We can execute this query:
old_key = 'foo'
new_key = 'new_foo'
User.update_all("custom_data = REPLACE(custom_data::text, '#{old_key}'::text, '#{new_key}'::text)::jsonb")
This will only replace the target key (old_key), inside our jsonb hash, without changing hash values or other hash keys.
Note ::text and ::jsonb type casting!
As far as I know, there is no easy way to update a serialized column in a data table en masse with raw SQL. The best way I can think of would be to do something like:
Car.find_each do |car|
mpg = car.car_details.delete("fuel_consumption")
car.car_details["mpg"] = mpg if mpg
car.save
end
This is assuming that you are using Active Record and your model is called "Car".
I want to know field name corresponding to table caption for a given model in Rails.
I am displaying captions using a query model.
query.columns.map{|q| q.caption}
=> ["Tracker", "Status", "Priority", "Subject", "Assignee", "Target version", "Due date", "% Done"]
Column has names corresponding to captions
query.columns.map{|q| q.name}
=> [:tracker, :status, :priority, :subject, :assigned_to, :fixed_version, :due_date, :done_ratio]
My model looks like
Issue.columns.map{|q| q.name}
=> ["id", "tracker_id", "project_id", "subject", "description", "due_date", "category_id", "status_id", "assigned_to_id", "priority_id", "fixed_version_id", "author_id", "created_on", "updated_on", "start_date", "done_ratio", "estimated_hours", "parent_id"]
I want to get field name(the db field name) corresponding to a caption from the above information.
Sample association in the model
belongs_to :assigned_to, :class_name => 'Principal', :foreign_key => 'assigned_to_id'
So for above association i want to know the foreign key.
for assigned_to i want 'assigned_to_id'
The reflections hash holds this kind of information:
Issue.reflections['assigned_to'].foreign_key
You can also get other information, such as the class (.active_record) or the type of association (.macro). Prior to rails 4.2, the keys of this hash are symbols and not strings.
The correct way for Rails 4.2 is:
Issue.reflections['assigned_to'].options[:foreign_key]
Note that "assigned_to" is a string according to API:
Returns a Hash of name of the reflection as the key and a
AssociationReflection as the value.
http://api.rubyonrails.org/classes/ActiveRecord/Reflection/ClassMethods.html#method-i-reflections
I'm posting this here in case this helps anyone else. I was trying to get the foreign key from proxy_association inside of an association extension.
You can get the reflection by simply using proxy_associtation.reflection.
Then, using #Frederick Cheung's method above, you can get the foreign_key like so:
reflection = proxy_association.reflection
reflection.foreign_key
You can also get the class_name in the same way:
reflection = proxy_association.reflection
reflection.class_name
I'd like to update a massive set of document on an hourly basis.
Here's the
fairly simple Model:
class Article
include Mongoid::Document
field :article_nr, :type => Integer
field :vendor_nr, :type => Integer
field :description, :type => String
field :ean
field :stock
field :ordered
field :eta
so every hour i get a fresh stock list, where :stock,:ordered and :eta "might" have changed
and i need to update them all.
Edit:
the stocklist contains just
:article_nr, :stock, :ordered, :eta
wich i parse to a hash
In SQL i would have taken the route to foreign keying the article_nr to a "stock" table, dropping the whole stock table, and running a "collection.insert" or something alike
But that approach seems not to work with mongoid.
Any hints? i can't get my head around collection.update
and changing the foreign key on belongs_to and has_one seems not to work
(tried it, but then Article.first.stock was nil)
But there has to be a faster way than iterating over the stocklist array of hashes and doing
something like
Article.where( :article_nr => stocklist['article_nr']).update( stock: stocklist['stock'], eta: stocklist['eta'],orderd: stocklist['ordered'])
UPDATING
You can atomically update multiple documents in the database via a criteria using Criteria#update_all. This will perform an atomic $set on all the attributes passed to the method.
# Update all people with last name Oldman with new first name.
Person.where(last_name: "Oldman").update_all(
first_name: "Pappa Gary"
)
Now I can understood a bit more. You can try to do something like that, assuming that your article nr is uniq.
class Article
include Mongoid::Document
field :article_nr
field :name
key :article_nr
has_many :stocks
end
class Stock
include Mongoid::Document
field :article_id
field :eta
field :ordered
belongs_to :article
end
Then you when you create stock:
Stock.create(:article_id => "123", :eta => "200")
Then it will automaticly get assign to article with article_nr => "123"
So you can always call last stock.
my_article.stocks.last
If you want to more precise you add field :article_nr in Stock, and then :after_save make new_stock.article_id = new_stock.article_nr
This way you don't have to do any updates, just create new stocks and they always will be put to correct Article on insert and you be able to get latest one.
If you can extract just the stock information into a separate collection (perhaps with a has_one relationship in your Article), then you can use mongoimport with the --upsertFields option, using article_nr as your upsertField. See http://www.mongodb.org/display/DOCS/Import+Export+Tools.
I'm looking for a way to store a serialized value of eg. IDs in a column. In before claims that this is not an optimal design: the column is used for IDs of associated records, but will only be used when displaying the record - so no queries are made with selection on the column and no joins will be made on this column either.
In Rails I can serialize the column by using:
class Activity
serialize :data
end
This encodes the column as YAML. For legacy sake and since I'm only storing one dimensional arrays containing only integers, I find it more suitable to store it as a comma-separated value.
I've successfully implemented basic accessors like this:
def data=(ids)
ids = ids.join(",") if ids.is_a?(Array)
write_attribute(:data, ids)
end
def data
(read_attribute(:data) || "").split(",")
end
This works pretty fine. However I'd like to add array-like methods to this attribute:
activity = Activity.first
activity.data << 42
...
How would I do this?
You can do it with composed_of feature as explained in this post.
It should be something like:
composed_of :data, :class_name => 'Array', :mapping => %w(data to_csv),
:constructor => Proc.new {|column| column.to_csv},
:converter => Proc.new {|column| column.to_csv}
after_validation do |u|
u.data = u.data if u.data.dirty? # Force to serialize
end
Haven't tested it though.
You can use serialize with a custom coder in rails 3.1.
See my answer to this question. :-)
How do you check what the datatype is for something that was retrieved from the database?
For example, if I have some instantiation of a model #model with a database field "title", I want to be able to code something like #model.title.type and have it return "String". Does Rails have any built-in functionality for this?
Try this:
#model.column_for_attribute('title').type
Should return :string, :text, :integer, etc.
The ActiveRecord Column class also includes a number of other attributes: default, limit, name, null, precision, primary, scale, sql_type, type.
In Rails 3, for my model "Firm", I'd use Firm.columns_hash.
Firm.columns_hash["name"].type #returns :string
If you want to iterate through them, you'd do something like this:
Firm.columns_hash.each {|k,v| puts "#{k} => #{v.type}"}
which will output the following:
id => integer
name => string
max_trade_qty => integer
and so on.