I have a rails model call MentorData and it has an attribute called os_usage
. The oses are stored in an array like so ['apple', 'linux']
.
To recap:
$ MentorData.first.os_usage
=> ['apple', 'linux']
I am looking to be able to query the data for all MentorData that includes the os_usage of apple
, but when I search MentorData.where(os_usage: 'apple')
I only get the mentors who can only use apple and not apple and linux. I need to search in some way that checks if apple is included in the array.
I have also tried the following.
MentorData.where('os_usage like ?', 'apple’)
MentorData.where('os_usage contains ?', 'apple’)
MentorData.where('os_usage contains @>ARRAY[?]', 'apple')
Is it possible to query data in ActiveRecord by attributes that have an array or items?
The database is on Postgres if that helps in providing a more raw search query.
You can avoid most n+1 queries in rails by simply eager loading associations. Eager loading allows you to load all of your associations (parent and children) once instead of n+1 times (which often happens with lazy loading, rails' default).
What is ActiveRecord? ActiveRecord is an ORM. It's a layer of Ruby code that runs between your database and your logic code. When you need to make changes to the database, you'll write Ruby code, and then run "migrations" which makes the actual changes to the database.
Rails Active Records provide an interface and binding between the tables in a relational database and the Ruby program code that manipulates database records. Ruby method names are automatically generated from the field names of database tables.
Here are the examples given in the current Rails Edge Guides for PostgreSQL:
# db/migrate/20140207133952_create_books.rb
create_table :books do |t|
t.string 'title'
t.string 'tags', array: true
t.integer 'ratings', array: true
end
add_index :books, :tags, using: 'gin'
add_index :books, :ratings, using: 'gin'
# app/models/book.rb
class Book < ActiveRecord::Base
end
# Usage
Book.create title: "Brave New World",
tags: ["fantasy", "fiction"],
ratings: [4, 5]
## Books for a single tag
Book.where("'fantasy' = ANY (tags)")
## Books for multiple tags
Book.where("tags @> ARRAY[?]::varchar[]", ["fantasy", "fiction"])
## Books with 3 or more ratings
Book.where("array_length(ratings, 1) >= 3")
Have you tried MentorData.where("'apple' = ANY (os_usage)")
?
Maybe you should detach the os_usage
array from your model and make it a separate table.
In ActiveRecord world you will get something like the following code:
class MentorData < ActiveRecord::Base
..
has_and_belongs_to_many :os_usage
..
end
class OsUsage < ActiveRecord::Base
..
has_and_belongs_to_many :mentors_data
..
end
Creating a many_to_many
relationship between this two models, allows you to query easily and avoid duplications. This technique is called normalization.
Using this new design you have your collection of os_usage made by objects instead of strings
MentorData.first.os_usage
# => [#<OsUsage:....>, #<OsUsage:...>]
Which you can convert easy into the old array of strings
MentorData.first.os_usage.map(&:name)
# => ['apple', 'linux']
In addition, you can query the data for all MentorData that includes the os_usage of apple:
MentorData.joins(:os_usages).where('os_usages.name' => 'apple')
And also query all the MentorData records for an OsUsage:
OsUsage.where(name: 'apple').mentors_data
I hope you find it useful :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With