I have a model Post
#<Post id: 121978, created_at: "2014-05-02 18:11:15", updated_at: "2014-05-02 18:11:15", data: {"hi"=>"1", "hello"=>"9999"}, review_id: nil>
And I'd like to sort them based on hello within the hstore datatype column data
I made this query:
Post.order("data -> 'hello'")
Which works but since Hstore is in string, I have 780, 78, 77, ... as an output.
I think you can cast the value as an integer before being processed by order. I'm not that familiar with Hstore, but here are some examples of how you might try to do that:
Post.order("CAST(data -> 'hello' AS INT)")
Post.order("CONVERT(INT, data -> 'hello')")
Post.order("(data -> 'hello') * 1")
Related
I am using Noticed gem for my notifications and I am trying to query for the notifications related to the post.
The notification stores the post as an object inside params.
#<Notification id: 10, params: {:post=>#<Post id: 3}>
I can target like
notification.params[:post][:id]
=> 3
What I am trying to accomplish is something like this:
Notifications.where(params[:post][:id] => 3)
Is there a way to do that or my approach should be different?
Edited:
Here is an example of a notification in the database:
#<Notification id: 10, recipient_type: "User", recipient_id: 8, type: "MessageNotification", params: {:user=>#<User id: 3, email: "test2#test2.com", created_at: "2021-01-06 23:34:46", updated_at: "2021-04-15 17:47:54", admin: true>, :conversation=>#<Mailboxer::Conversation id: 6, subject: "Hello", created_at: "2021-05-14 00:14:41", updated_at: "2021-05-14 00:26:06">}, read_at: nil, created_at: "2021-05-14 00:26:06", updated_at: "2021-05-14 17:11:50">
squema.rb
t.jsonb "params"
A query suggested by #Joel_Blum and the slq call:
>> current_user.notifications.where('params #> ?', {conversation: {id: 6}}.to_json).to_sql
=> "SELECT \"notifications\".* FROM \"notifications\" WHERE \"notifications\".\"recipient_id\" = 8 AND \"notifications\".\"recipient_type\" = 'User' AND (params #> '{\"conversation\":{\"id\":6}}')"
Returns => #<ActiveRecord::AssociationRelation []>
It seems the gem creates either a jsonb or json column depending on your db.
So what want is perform a search on a json(b) column
For postgres for example it can be done like this
Notification.where('params #> ?', {post: {id: 3}}.to_json)
For whatever reason I am getting an empty array on a notification that I am sure exists.
query: Notification.where('params #> ?', {comment: {id: testc.id}}.to_ json)
SQL: "SELECT \"notifications\".* FROM \"notifications\" WHERE (params #> '{\"comment\":{\"id\":656}}')"
Noticed has a built in way of querying for objects you send in the params.
If you add has_noticed_notifications to the Post model, you should then be able to call #post.notifications_as_post
This is in the Noticed readme here. I definitely came here and found this question before I found the details in the readme!
I'm working on learning Active Record and queries and wrote a query within my rails console that I thought should work pretty easily, but it is not.
Statistic.select("player_id, sum(oreb)").group("player_id").limit(5)
This returns the following Active Record Relation
[#<Statistic:0x007f801b2f0240 id: nil, player_id: 1>, #<Statistic:0x007f801b2f00b0 id: nil, player_id: 2>, #<Statistic:0x007f801fcffed0 id: nil, player_id: 3>, #<Statistic:0x007f801fcffd40 id: nil, player_id: 4>, #<Statistic:0x007f801fcffbb0 id: nil, player_id: 5>]
oreb does exist, i can use pgAdmin or the psql console tool to execute the query directly
Select player_id, sum(oreb) from Statistics
GROUP BY player_id
LIMIT 5
And get the a result that includes oreb.
I've done a bit of research, and can't find a simple reason for why this is not working...any thoughts would be appreciated...
Model Statistic doesn't have column for sum(oreb) and can't be mapped to model's attributes but data is retrieved. You can extract it by given name to sum.
stats = Statistic.select("player_id, sum(oreb) total").group("player_id").limit(5)
puts stats.first.total
record = #<ActiveRecord::AssociationRelation
[#<User id: 2, store_id: 3,location: 'xxx'>,
#<User id: 4, store_id: 3,location:'yyy'>,
#<User id: 5, store_id: 4,location:'zzz'>,
#<User id: 6, store_id: 4,location:'aaa'> ]>
How to group location in comma seperated form based on store_id in ruby to get the result as,
The location of store-id(3) should be combained with comma as (yyy,xxx),
then the location of store-id(4) should be combained with comma as (zzz,aaa)
#< store_id: 3,location:'yyy,xxx'>
#< store_id: 4,location:'zzz,aaa'>
Using Enumerable.group_by you can do it this way:
User.all.group_by(&:store_id).map{|store_id,records| {store_id: store_id, location: records.map(&:location).join(',')}}
If you want to do the grouping on database level, using the group method from ActiveRecord, it is required to have a function on the database that takes care of the concatenation, so the solution would depend on the database being used.
For example, in MySQL (see Can I concatenate multiple MySQL rows into one field?)
User.group("store_id").select("store_id, GROUP_CONCAT(location SEPARATOR ',') as location")
I have an array of hashes with various records in them. I have a value which I want to cross reference against that array and if it matches, pull out that record and use it.
>> concurrent_jobs.job_products
=> #<ActiveRecord::Associations::CollectionProxy [#<JobProduct id: 365, job_id: 91, product_id: 181, quantity: 3, frozen_cache: {}, created_at: "2014-08-13 15:54:21", updated_at: "2014-08-14 09:56:37">, #<JobProduct id: 366, job_id: 91, product_id: 363, quantity: 1, frozen_cache: {}, created_at: "2014-08-13 16:02:40", updated_at: "2014-08-13 16:02:40">]>
So let's say in the above array I want to collect the entire record that matches product_id: 363 and then begin to use its other information such as quantity etc. How do I do it?
here is the method I have written so far
def product_quantity_in_current_unconfirmed_jobs(concurrent_jobs, original_product)
concurrent_jobs.job_products.map do |x|
b = x.product.id
if b == original_product.id
raise
end
end
end
I am sure there is a more eloquent way to do this. I'm just learning
Assuming that this is an ActiveRecord association, you probably just want to query the association directly:
concurrent_jobs.job_products.where(product_id: 363).first
This will execute a SQL query to return just that one record (you can see that query by tailing your log/development.log), rather than returning all the records and forcing you to iterate them in your app.
That said, in the general case, if this were not ActiveRecord and you had an array of hashes, you could use Enumerable#select (to grab all matching records) or Enumerable#detect (to grab the first matching record):
matching_records = array.select {|entry| entry[:product_id] == 363 }
or:
first_matching_record = array.detect {|entry| entry[:product_id] == 363 }
Suppose I have Users data that store array of pet in String datatype
[
#<User id: 1, name: "John", pets: "---\n- cat\n- dog\n- bunny\n- ''\n">,
#<User id: 2, name: "Pete", pets: "---\n- dog\n- bunny\n- ''\n">,
#<User id: 3, name: "Jack", pets: "---\n- cat\n- ''\n">,
#<User id: 4, name: "Kurt", pets: "---\n- cat\n- bunny\n- ''\n">
]
Can i get all users that has a cat? Maybe something like User.find_all_by... or User.where(....) or anything that return as a relation? So i can order with active record query.
I know i can get all users that has a cat with
User.all.select{|s| YAML.load(s.pets).include?'cat'}
, but it convert to array that cannot be ordered with active record query.
thx for helping.
You could use simple SQL to see if 'cat' shows up in the serialized column.
User.where('pets LIKE "%cat%"').all
You need to normalize your data, add Pet model and set has_and_belongs_to_many association between theese models.