Rails 5 - How to use postgresql query? - sql

In rails 5, I am using pg(postgresql) for a back-end database. Now I want to query through rails and get the data. How can I use IN and ORDER(:created_at, :desc) conditions in a query.
In controller,
PAGE_LIMIT = 5
posts = Post.where("user_id IN (?)", [1,2,3]).order(created_at: :desc)
posts = posts.paginate(params[:page], PAGE_LIMIT)
I am writing a custom method like,
def paginate(page, limit = 5)
page = page ? page.to_i : 1
limit = limit.to_i
offset = (page - 1) * limit
self.offset(offset).limit(limit)
end
I am new to postgresql. Please help me to solve this issue?

suppose you have User model and you want to get user which has id in [1,2,3]
User.where("id IN (?)", [1,2,3]).order(created_at: :desc)
for more dynamic
x = [1,2,3]
name = "testing123"
User.where("name = ? AND id IN (?)", name, x).order(created_at: :desc)
for more details you can see Active Record Query
to make it working with pagination for array changes to be done here
modified answer
PAGE_LIMIT = 5
posts_arr = Post.where("user_id IN (?)", [1,2,3]).order(created_at: :desc)
posts = Post.where(id: posts_arr.map(&:id)) #here to get active records of posts to make it working for custom pagination
posts = posts.paginate(params[:page], PAGE_LIMIT)

Related

sqlalchemy: paginate does not return the expected number of elements

I am using flask-sqlalchemy together with a sqlite database. I try to get all votes below date1
sub_query = models.VoteList.query.filter(models.VoteList.vote_datetime < date1)
sub_query = sub_query.filter(models.VoteList.group_id == selected_group.id)
sub_query = sub_query.filter(models.VoteList.user_id == g.user.id)
sub_query = sub_query.subquery()
old_votes = models.Papers.query.join(sub_query, sub_query.c.arxiv_id == models.Papers.arxiv_id).paginate(1, 4, False)
where the database model for VoteList looks like this
class VoteList(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
arxiv_id = db.Column(db.String(1000), db.ForeignKey('papers.arxiv_id'))
vote_datetime = db.Column(db.DateTime)
group = db.relationship("Groups", backref=db.backref('vote_list', lazy='dynamic'))
user = db.relationship("User", backref=db.backref('votes', lazy='dynamic'), foreign_keys=[user_id])
def __repr__(self):
return '<VoteList %r>' % (self.id)
I made sure that the 'old_votes' selection above has 20 elements. If I use .all() instead of .paginate() I get the expected 20 result?
Since I used a max results value of 4 in the example above I would expect that old_votes.items has 4 elements. But it has only 2? If I increase the max results value the number of elements also increases, but it is always below the max result value? Paginate seems to mess up something here?
any ideas?
thanks
carl
EDIT
I noticed that it works fine if I apply the paginate() function on add_columns(). So if I add (for no good reason) a column with
old_votes = models.Papers.query.join(sub_query, sub_query.c.arxiv_id == models.Papers.arxiv_id)
old_votes = old_votes.add_columns(sub_query.c.vote_datetime).paginate(page, VOTES_PER_PAGE, False)
it works fine? But since I don't need that column it would still be interesting to know what goes wrong with my example above?
Looks to me that for the 4 rows returned (and filtered) by the query, there are 4 rows representing 4 different rows of the VoteList table, but they refer/link/belong to only 2 different Papers models. When model instances are created, duplicates are filtered out, and therefore you get less rows. When you add a column from a subquery, the results are tuples of (Papers, vote_datetime), and in this case no duplicates are removed.
I encountered the same issue and I applied van's answer but it did not work. However I agree with van's explanation so I added .distinct() to the query like this:
old_votes = models.Papers.query.distinct().join(sub_query, sub_query.c.arxiv_id == models.Papers.arxiv_id).paginate(1, 4, False)
It worked as I expected.

Rails: Query n IDs before and after some ID

I would like to query n users before and after some user.
Edit: for clarity
def local_query(id, range)
local_min = id - range*0.5
local_max = id + range*0.5
local_users = User.where(id: [local_min..local_max])
return local_users
end
Guessing that you want to query user by limiting ID(specific range of ID) i think following should work
user_id_min_range = 5
user_id_max_range = 10
User.where(id: (user_id_min_range..user_id_max_range))
Above code will return users whose ID are between 6-10
Or you can also do like following
User.where("id > ?", 5).order(id: :asc).limit(5)
Above query will select users with id greater than 5 and order them in Ascending ID and return top 5 users.
If I understand your question correctly you could use this scopes:
scope :next_users, ->(start_id, user_limit) {
order(id: :asc).where("id > ?", start_id).limit(user_limit)
}
scope :before_users, ->(start_id, user_limit) {
order(id: :desc).where("id < ?", start_id).limit(user_limit)
}
They will select n of the next or before users for a predefined user id.

Rails SQL Where Count

I have a Posts Table and A Sec_photo table :
class Post < ActiveRecord::Base
has_many :sec_photos
I am trying to do an advanced search form where it finds posts based on their sum of sec_photos :
#posts = #posts.where(:sec_photos.count > 2) is failing and I have looked online and attempted many other solutions but none seem to work.
Does anyone have any ideas?
Ps: It's a necessity for the line to be in the form #posts = #posts.where as that coincides with other conditions.
The advanced search from searches for other fields like category_id and location_id as such
#posts = Post.all
#posts = #posts.where('category_id = ?', #advanced_search.category_search) if #advanced_search.category_search.present?
#posts = #posts.where('location_id = ?', #advanced_search.location_search) if #advanced_search.location_search.present?
#posts = #posts.where("strftime('%m %Y', created_at) = ?", #advanced_search.newdate_search.strftime('%m %Y')) if #advanced_search.newdate_search.present?
The last option would be to show posts with sec_photos either more than 2 or less than 2
You can do as following:
#posts = Post.whatever_scopes_you_use
#posts = #posts.joins(:sec_photos).group('posts.id').having('COUNT(sec_photos.id)
> 2')
This last line will select all posts having strictly more than 2 sec_photos associated. Of course, you can easily make a scope from this, accepting a count variable to make it dynamic ;-)
From my previous answer: How to return results filtered on relations count to a view in RAILS?

Rails .where(.... and ....) Searching for two values of the same attribute

I've tried
#users = User.where(name: #request.requester or #request.regional_sales_mgr)
and
#users = User.where(name: #request.requester).where(name: #request.regional_sales_mgr).all
This doesn't seem to work. What I want is to find the user whose name matches #request.requester, and the user whose name matches #request.regional_sales_mgr, and save them both into the variable #users.
In the general case "OR" queries can be written as:
User.where("users.name = ? OR users.name = ?", request.requester, request.regional_sales_mgr)
Note: Rails 5 will support OR using:
User.where(name: request.requester).or(User.where(name: request.regional_sales_mgr))
For this specific case as state in other answers an IN query is simpler:
User.where(name: [request.requester, request.regional_sales_mgr])
You want to use the SQL IN clause. Activerecord provides a shortcut to this:
#users = User.where(name: [#request.requester, #request.regional_sales_mgr]).all
Giving an array of values to name: will generate the following SQL statement:
SELECT * FROM users WHERE name IN (value1, value2, and so on...);
This should find all the users whose names are #request.requester or #request.regional_sales_mgr
Diego's answer should solve Sabrams' question without the all in rails 4.x (query for user with a name of x or y)
#users = User.where(name: [#request.requester, #request.regional_sales_mgr])
For those who find this post like I did actually looking for a rails all, you can chain where's. For instance to only get users that have both of two skills through a join table. (This will returns users with both x and y skill, will not return user with only x)
#users = User.joins(:skillable_joins).where(skillable_joins: { skill_id: 1 }).where(skillable_joins: { skill_id: 2 })

ActiveRecord how to correctly exclude records with conditions correctly?

Why does below not work?
Try to exclude all the is_reply = 1 values from the query but can't figure out how to.
I tried several combinations but all fail.
All records with is_reply = 1 still get returned with this below query, I think need to sub the or part but how?
#messages = Message.all(:conditions => ['is_reply = ? AND recipient_id
= ? OR user_id = ?', 0, current_user.id, current_user.id] )
You probably want to use parenthesis() and group your conditions together
['is_reply = ? AND (recipient_id = ? OR user_id = ?)', 0, current_user.id, current_user.id]