Rails query include? an array - ruby-on-rails

I store an array of Section ids as integers. event.sections #=> ["1","115","130"]
There is no Events has_many Sections relationship. Maybe this is a problem. I only need id's from Section and nothing else, so I have the array of integers stored as a serialized string in Postgres.
I can do something like this, which returns an array of events:
Event.upcoming.select { |m| m.sections.include? #section.id.to_s}
Is there a way to query this to get back an ActiveRecord::Relation?
edit-----
My earlier select query is not correct, because if #section.id = "1" then it will match and select events with these id's "1", "10", "21", "100"
This is the proper select statement:
Event.upcoming.select {|e| ( e.newsletters.split(",").flatten.grep /^#{#section.id.to_s}$/ ).presence }

Related

Ruby on Rails and POSTgres: Search IN an array within JSON field [duplicate]

I have a table with a jsonb column that has a nested json array. I would like to find all records where the nested array contains at least one of a value.
For instance, my model Person has a jsonb column named preferences. Inside the jsonb preferences, there are a few keys, one of which the value is an array:
Person.first.preferences = {"diet" => {"foods" => ["apples", "oranges", "bananas"]}}
I would like to create a query that returns all Persons whose preferences -> diet -> foods include 'apples' OR 'mangos' (for example).
Currently, I can get results with 1 input (ie. 'apples') like this:
Person.where('preferences #> ?', {'diet' => {'foods' => ['apples']}}.to_json)
And multiple inputs, if they all exist in the array. So if I pass in 'apples' and 'oranges', the result is returned because the record includes BOTH apples and oranges.
Person.where('preferences #> ?', {'diet' => {'foods' => ['apples', 'oranges']}}.to_json)
Is there a way to pass in multiple variables (ie. ['apples', 'mangos']) and check if the nested jsonb array contains either apples OR mangos but not necessarily both?
The following query has no results, because my Person's food preferences don't include mangos, even though they include apples.
Person.where('preferences #> ?', {'diet' => {'foods' => ['apples', 'mangos']}}.to_json)
Using Rails 5.2 and Postgresql 10
Thanks!
The first thing to do is to get to the array using -> or #> and then you can use the ?| operator to check if the array overlaps what you're looking for. Something like this SQL:
preferences->'diet'->'foods' ?| array['apples', 'mangos']
or with ActiveRecord:
Person.where("preferences->'diet'->'foods' ?| array[:foods]", foods: ['apples', 'mangos'])

Hstore Query to find records matching with any array element using ruby on rails

I've a hstore field in a database table. I want to write a Query to find records matching with any array element in any hash of hstore field using ruby on rails.
Users Table
--------------------------------------------------------------------------------
ID Name sectors(hstore)
1 Piotr {"aviation"=>"0", "oil_and_gas" => "50", "transport" => "50"}
2 reza {"oil_and_gas" => "70", "energy" => "30"}
3 pat {"transport" => "40", "energy" => "60"}
4 Kim {"infrastructure" => "20", "healthcare" => "20", "industrial" => "60"}
considering above test data, I want to write a query on hstore field to get all records having any key like ['oil_and_gas', 'energy', 'transport']
I can match and find single sector records as its mentioned in https://nandovieira.com/using-postgresql-and-hstore-with-rails, but my requirement is to find any record where hstore hash is having any one key matching with any one element of array.
I'm using Rails 5.1.6.2, ruby 2.5.3
May be you are looking for the following operator:
hstore ? key # does hstore contain key?
Query may looks like so:
User.where("sectors ? 'oil_and_gas'")
.or("sectors ? 'energy'")
.or("sectors ? 'transport'")
According to postgresql docs
Check for a specific key in hstore column You can check for a specific
key in an hstore column using the ? operator in the WHERE clause. For
example, the following statement returns all rows with attr contains
key publisher.
SELECT
title,
attr->'publisher' as publisher,
attr
FROM
books
WHERE
attr ? 'publisher';

Ruby on Rails Activerecord 'where' for array filtering

I have a Meal model with an ingredients attribute. The ingredients attribute is a multidimensional array eg. ingredients: => [[ 1, 5, "g"], [ 2, 5,"ml"], [3, 10,"tsp"]]. The first value in each inner array is an ingredient id.
My search params give an array of ingredient ids, eg. ingredients"=>["3", "67"]
I know I can iterate through all the meals and compare with the search parameters with .each do etc, but I would like to use .where so I can better limit results. Is this possible?
I'm not sure how to select the first item of each inner array to compare with the search parameters. I have tried a few variations but either get formatting errors or no results.
If search = ["3", "67"] (example ingredient ids)
Meal.where('ingredients IN (?)', "#{search}") (No results)
Meal.where('ingredients[][0] IN (?)', "#{search}") (This gives an error)

sort by values not present in the database

I would like to sort objects, but i want this sorting to not be based on the direct value i have stored in the database.
In the database there are integer values, 1,2,3... but there is also a hash, that specifies, what those values mean.
{1 => "a", 2 => "za", 3 => "xa"}.
So if an instance has value 3, it should be sorted as "xa". Can I achieve this goal with order() method? It is important to not use arrays, but rather ActiveRecord Relations
For the making of a temp_table and populate it with the values of your hash, this should work.
sqlQuery1 = ActiveRecord::Base.connection.execute("CREATE TEMP TABLE IF NOT EXISTS hash_tmp(id integer, hash_values integer)")
sqlQuery2 = ActiveRecord::Base.connection.execute(TRUNCATE hash_tmp)
Your_hash.each do |id, value|
sqlQuery3 = ActiveRecord::Base.connection.execute("INSERT INTO hash_tmp(id, hash_values) VALUES (#{id}, '#{value}')")
end
You should have a model for that temp table you created, then you can get all the values (filtered or not) and order by the new field:
#YourTemp = Yourtemp_model.all(:order=> "hash_values")
This is assuming that to this point your hash holds all the possible values which means you can iterate it and populate your temp table with them.

Best way to order records by predetermined list

In order to keep things simple I have avoided using an enum for an attribute, and am instead storing string values.
I have a list of all possible values in a predetermined order in the array: MyTypeEnum.names
And I have an ActiveRecord::Relation list of records in my_recs = MyModel.order(:my_type)
What is the best way to order records in my_recs by their :my_type attribute value in the order specified by the array of values in MyTypeEnum.names ?
I could try this:
my_recs = MyModel.order(:my_type)
ordered_recs = []
MyTypeEnum.names.each do |my_type_ordered|
ordered_recs << my_recs.where(:my_type => my_type_ordered)
end
But am I killing performance by building an array instead of using the ActiveRecord::Relation? Is there a cleaner way? (Note: I may want to have flexibility in the ordering so I don't want to assume the order is hardcoded as above by the order of MyTypeEnum.names)
You are definitely taking a performance hit by doing a separate query for every item in MyTypeEnum. This requires only one query (grabbing all records at once).
ordered_recs = Hash[MyTypeEnum.names.map { |v| [v, []] }]
MyModel.order(:my_type).all.each do |rec|
ordered_recs[rec.my_type] << rec
end
ordered_recs = ordered_recs.values.flatten
If MyTypeEnum contains :a, :b, and :c, ordered_recs is initialized with a Hash of Arrays keyed by each of the above symbols
irb(main):002:0> Hash[MyTypeEnum.names.map { |v| [v, []] }]
=> {:a=>[], :b=>[], :c=>[]}
The records are appended to the proper Array based on it's key in the Hash, and then when all have bene properly grouped, the arrays are concatenated/flattened together into a single list of records.

Resources