How to search psql array elements by index in rails - ruby-on-rails

In my rails psql application I have an emails array column. The element in the first index of this column is the primary email. I want to be able to search the db for all people with primary email x.

No need to test for array inclusion. Just get the first element and compare that to the string:
User.where("emails[1] = ?", "x#test.com")

I could not see this in the documentation but thanks to this answer I can see that in Postgres 9.5 or older you can use
arr[1:1]
syntax to look only in the first element
So this is the answer
User.where("emails[1:1] #> ARRAY[?]", "x#test.com")

Related

Grouping by into a list with activerecord in rails

I need to achieve something exactly similar to How to get list of values in GROUP_BY clause? but I need to use active record query interface in rails 4.2.1.
I have only gotten so far.
Roles.where(id: 2)
.select("user_roles.id, user_roles.role, GROUP_CONCAT(DISTINCT roles.group_id SEPARATOR ',') ")
.group(:role)
But this just returns an ActiveRecord::Relationobject with a single entry that has id and role.
How do I achieve that same with active record without having to pull in all the relationships and manually building such an object?
Roles.where(id: 2) already returns the single record. You might instead start with users and join roles table doing something like this.
User.
joins(user_roles: :roles).
where('roles.id = 2').
select("user_roles.role, GROUP_CONCAT(DISTINCT roles.group_id SEPARATOR ',') ").
group(:role)
Or, if you have the model for user_roles, start with it since you nevertheless do not query anything from users.

Activerecord query against array column using wildcard

So let's say i have a Customer model with array column phones.
It's pretty easy to find all customers with given phone
Customer.where('? = ANY(phones)', '+79851234567')
But i can't figure out how to use LIKE with wildcard when i want to find customers with phones similar to given one, something like:
Customer.where('ANY(phones) LIKE ?', '+7985%')
I'm using PostgreSQL 9.5 and Rais 4.2
Any ideas?
I think, first of all, its better to use second table phones with fields customer_id, phone_number. I think it's more rails way ). In this way you can use this query
Phone.where("phone_number LIKE ?", '%PART%').first.customer
If you serialize your array in some text field, by example JSON, you should use % on both sides of your pattern:
Customer.where('phones LIKE ?', '%+7985%')
If you have an array in your database, you should use unnest() function to expand an array to a set of rows.
Can you try this
Customer.where("array_to_string(phones, ', ') like ?", '+7985%')
I believe this will work.

Rails NOT IN query and regexp

I have array of strings:
a = ['*#foo.com', '*#bar.com', '*#baz.com']
I would like to query my model so I will get all the records where email isn't in any of above domains.
I could do:
Model.where.not(email: a)
If the list would be a list of strings but the list is more of a regexp.
It depends on your database adapter. You will probably be able to use raw SQL to write this type of query. For example in postgres you could do:
Model.where("email NOT SIMILAR TO '%#foo.com'")
I'm not saying thats exactly how you should be doing it but it's worth looking up your database's query language and see if anything matches your needs.
In your example you would have to join together your matchers as a single string and interpolate it into the query.
a = ['%#foo.com', '%#bar.com', '%#baz.com']
Model.where("email NOT SIMILAR TO ?", a.join("|"))
Use this code:
a = ['%#foo.com', '%#bar.com', '%#baz.com']
Model.where.not("email like ?",a.join("|"))
Replace * to % in array.

Find values greater than using hstore and rails

I am storing product information, including the release year of the product, using hstore and postgresql in rails. Now I would like to be able to query for all products that was released before or after a specific year. I am able to query for all records containing the year field in the 'data' hstore column using:
Product.where("data ? 'year'")
Due to hstore the year value is stored as a string. Therefore, I have tried to type cast the year to an integer in order to find records with years greater than/less than X:
Product.where("(data ? 'year')::int > 2011")
However, this does not seem to work, I always get an empty array of results in return. What am I doing wrong? Is there another way to do this?
I think the operator your are looking for is ->.
So, try this : where("(data -> 'year')::int > 2011")
(from jO3w's comment)

Ruby-on-Rails: Selecting distinct values from the model

The docs:
http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields
Clearly state that:
query = Client.select(:name).distinct
# => Returns unique names
However, when I try that in my controller, I get the following error:
undefined method `distinct' for #<ActiveRecord::Relation:0xb2f6f2cc>
To be clear, I want the distinct names, like ['George', 'Brandon'], not the clients actual records. Is there something that I am missing?
The .distinct option was added for rails 4 which is what the latest guides refer to.
Rails 2
If you are still on rails 2 you will need to use:
Client.select('distinct(name)')
Rails 3
If you are on Rails 3 you will need to use:
Client.select(:name).uniq
If you look at the equivalent section of the rails 3 guide you can see the difference between the two versions.
There are some approaches:
Rails way:
Model.select(:name).distinct
Semi-rails way
Model.select("DISTINCT ON(models.name) models.*")
The second allows you to select the first record uniqued by name, but in the whole matter, not only names.
If you do not want ActiveRecord::Relations returned, just an array of the names as strings, then use:
Client.distinct.pluck(:name)
To get an ordered result set:
Client.order(:name).distinct.pluck(:name)
This will work for Rails 2 (pretty old rails I know!), 3 and 4.
Client.select('distinct(name)')
This will actually use the SQL select distinct statement
SELECT distinct name FROM clients

Resources