How do I query by an attribute when that attribute is an array and I'm looking for a certain value within that array - sql

I have a User model, and a user has many seniors. I want to return all user records who's senior_ids column contains id= x. The best I could come up with was User.where("? IN senior_ids", x), but that did not work. Any suggestions?

It seems that your design is slightly wrong here. You should use has_and_belongs_to_many association (or has_many :through) to connect users and seniors. You can read about those under a link in nzifnab's comment. Then you could simply write:
senior.users
With current design you can go with:
User.all.select {|user| user.senior_ids.include? x}
however it is gona be really slow and horribly ugly. Keeping serialized array of ids is in general a very bad idea.

Related

Select specific entities to be tagged

Is it possible to only have NER tag a subset on entities. For example I may only need the date and money entities how could I accomplish that?
I’ve looked through the EntityRecognized documentation but didn’t see anything around removing entities.
It looks like it might be possible to accomplish this by retraining the NER tagger. (If you're interested in this route, check out this article that discusses your problem.)
But are you absolutely sure it's necessary though?
For instance, you could create a method that filters the results so that it only returns the entity types you are looking for.
def get_entities(doc):
for entity in doc.ents:
if entity.label_ in ["DATE","MONEY"]:
yield entity
else:
continue
Then instead of iterating over doc.ents, you can iterate over get_entities(doc) instead.
This seems like the easier way to me.

Inverse of IN in Rails

I feel foolish, but I cannot find the answer to this.
If I have a User with many attributes, given a list of attributes, I can ask rails something like this:
User.where("attributes.id IN ?", list_of_attribute_ids)
With the appropriate joins or includes or whatever.
However, I have no idea how to find the inverse set of those users. That is, given 100 users, if the result return 75 entries, I don't know how to find the other 25!
I thought
User.where("attributes.id NOT IN ?", list_of_attribute_ids)
might work (similarly, User.where.not), but it doesn't! Instead, it looks for those users where any of their attributes are not one of the list, which is useful, but not what I want.
The only way I know how to do it, is with something like:
User.where.not(id: User.where("attributes.id IN ?", list_of_attribute_ids).pluck(:id))
Which is sort of like the SQL for select user where id not in (gather a list of ids).
But this is massively non-performant, and generally just can't cope with a database with more than a few (hundred) entries.
How do you do this?
I think you could use left outer joins, like #Vishal mentioned in the comments.
See the guides: http://guides.rubyonrails.org/active_record_querying.html#left-outer-joins
rails 4:
joins("LEFT OUTER JOIN <something>")
rails 5:
left_outer_joins(:something)

sql count filtering - rails way

Suppose I have Posts and posts' Comments. I want to filter all the Posts that have more than 10 comments. I began writing something like Posts.includes(:comments).group("post.id").count("comments.id"), to obtain a hash of posts and their counts, and I can extract the information from there, but I want some one-line straightforward way to do that
Sure I can use some pure sql syntax statements, but I want it in a pure rails way. Any idea ?
Assuming the models are named in the more typical singular form of Post and Comment and have the usual association relationship, then the following should work:
Post.joins(:comments).group('posts.id').having('count(comments.id) > 10')

Avoiding db hits in ActiveRecord

When I assign a database find to an instance variable in Rails, why do future requests to that variable also hit the database? Can this be avoided?
For example, I have 3 models: User, Resource, Opinion, with has_many :through on Opinion
#opinions = current_user.opinions # pulls in all of the user's opinions, which include respective resource ids
1. Calling for resource_id directly does not hit the database:
#opinions.each do |opinion|
opinion.resource_id # does not hit the database (as expected)
end
2. Performing a query does hit the database (even though variable has been assigned):
#opinions.find_by_resource_id(1) # DOES hit the database
Why does #2 hit the database? Is there a way to perform the same find without hitting the database?
The information is already contained in the #opinions variable, so a db call does not seem necessary.
If you don't need anything else in the #opinions array, I would scope your original query to only include opinions with that resource_id
#opinions = current_user.opinions.where("resource_id = ?", resource_id)
If you already have #opinions and just want to create a new array of objects that match for a specific key/value:
#opinions_with_resource_id = #opinions.select { |opinion| opinion.resource_id == 1234 }
Check out this other answer for another explanation or if you want to split the answer into multiple arrays.
Thoughts
Comment on your last piece of code
Methods like you called find_by_* are dynamic finders that use method_missing to hit the database and look inside of the column specified by the *.
Remaining comments from previous answer
If this object will ever need to access data on the Resource model, don't forget about the #includes() method, which will keep you from having to run additional queries down the road.
#opinions = current_user.opinions.includes(:resources)
See http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

How to resuse deleted model id number in Rails?

Say I have a Post model. When I delete last post 'Post 24', I want the next post to take id of Post 24 and not Post 25.
I want to show id in views and I don't want missing numbers. How do I do that?
Thanks for your help.
The purpose of an id is to be nothing more than an internal identifier. It shouldn't be used publicly at all. This isn't a Rails thing, but a database issue. MySQL won't reclaim id's because it can lead to very serious complications in your app. If a record is deleted, its id is laid to rest forevermore, so that no future record will be mistaken for it.
However, there is a way to do what you want. I believe you want a position integer column instead. Add that to your model/table, and then install the acts_as_list plugin.
Install it the usual way:
script/plugin install git://github.com/rails/acts_as_list.git
Then add the "hook" to your model:
class Post < ActiveRecord::Base
acts_as_list
end
Now the position column of your post model will automatically track itself, with no sequence gaps. It'll even give you some handy methods for re-ordering if you so choose.
Conversely, you could let the SQL do this itself:
SELECT rownum AS id, [whatever other columns you want]
FROM posts_table
WHERE [conditions]
ORDER BY [ordering conditions]
This will add numbers to each row without skipping any like you said.
NOTE: I use Oracle. I don't know if this exact code will work in other flavors.