Query of searchkick get wrong result - ruby-on-rails

Query of searchkick get wrong result.
I have this one record in db:
2.2.0 :047 > Product.first
#<Product id: 1, title: "Ball", description: "<p>Ball</p>\r\n", price: 10, material: "lalala", created_at: "2015-04-21 04:30:53", updated_at: "2015-04-21 04:30:53", preview: "images__1_.jpg", count: 20>
in controller Product and action search i have this code:
def search
#products = Product.search "*", where:
{
count: 10..18
}
end
and after this, a get result, that the with this values, count is exist.
But in db count = 20. And all time, get wrong result. I don't know why?

I get not correct result, 'cause i don't have hash, in model and need reindex of Model.
In model:
def search_data
{
count: count,
price: price,
title: title,
category_id: categories.map($:id)
}
end
and after that, in rails console wrote:
Product.reindex

Related

Making leader board

I'm working with Stats of players and I got this data.
Stat model = id: integer, pts: float, user_id: integer, created_at: datetime, updated_at: datetime
So there is a chance that user_id has 2 or more data.
{id: 1, pts: 2, user_id: 1, created_at: datetime, updated_at: datetime}
{id: 2, pts: 8, user_id: 1, created_at: datetime, updated_at: datetime}
{id: 3, pts: 10, user_id: 2, created_at: datetime, updated_at: datetime}
I need to get the average pts per user_id then order it by pts. To get the top scorer.
EDIT
I've fixed this using:
stat = Stat.group(:user_id).sum("pts")
new_value = Hash[*stat.sort_by { |k,v| -v }[0..9].flatten] # To get top 1 to 10
Thank you!
You can do it with a simple query:
hash = Stat.group("user_id").average('pts')
Its will return a hash containing user_id as key and their average points scored as value.
Now to order you can order this hash as:
Hash[h.sort_by{|k, v| v.to_i}.reverse]
This will return a hash sorted in descending order by points.That means the first element in the hash would be the top scorer.
Note: v.to_i is use to handle nil cases.
Try this...
Stat.group(:user_id).order('average_pts DESC').average(:pts)
Other option.
In controller:
#users = User.joins(:stats).select("users.*, stats.user_id, stats.pts, AVG(stats.pts) avg_pts").group('stats.user_id').order("avg_pts DESC")
In view, to be formatted as you like:
<% #users.each do |user| %>
<p><%= user.name %> | <%= user.avg_pts %></p>
<% end %>

Why do I receive undefined method after dynamically building array of Objects? Ruby

I'm building a most viewed post feature for a simple blog. Each post has a view count that is increased when the Show action is called for that particular post. Then on the Dashboard , I'm trying to list the top 5 posts. So far my code works and returns an array of posts with the post with the highest number of view count being the first index and the last index in the array being the post with the lowest view count. The only thing is when I try to iterate through the array in the view , the view returns:
ERROR
undefined method `title' for nil:NilClass
WHY??? Does it have to do with the "#" infront of the object?
Heres my code.
Dashboard View
<h3> Post </h3>
<% #top_posts.each do |post| %>
<%= post.title %>
<% end %>
Controller Methods
def get_top
#top_posts = []
counts = []
#posts = Post.all
#posts.each do |post|
counts << post.view_count
end
#posts.each do |post|
if counts.max(5).include?(post.view_count)
counts.max(5).each do |n|
if n == post.view_count
#top_posts[counts.max(5).index(n)] = post
end
end
end
end
end
def dashboard
#posts = Post.all
get_top
end
The Top Podcast Array of objects
[#<Post id: 6, title: "Post 6", desc: "", tags: "", view_count: 8, s_desc: "", c_photo: nil, photos: nil, created_at: "2017-06-14 06:02:25", updated_at: "2017-06-15 01:38:40", featured: nil>, #<Post id: 3, title: "post 3", desc: "", tags: "", view_count: 5, s_desc: "", c_photo: nil, photos: nil, created_at: "2017-06-14 05:35:32", updated_at: "2017-06-14 05:35:53", featured: nil>, #<Post id: 5, title: "Post 5", desc: "", tags: "", view_count: 4, s_desc: "", c_photo: nil, photos: nil, created_at: "2017-06-14 06:02:20", updated_at: "2017-06-15 01:38:31", featured: nil>, nil, #<Post id: 4, title: "Post 4", desc: "", tags: "", view_count: 3, s_desc: "", c_photo: nil, photos: nil, created_at: "2017-06-14 05:49:29", updated_at: "2017-06-15 01:38:50", featured: nil>]
The other answer would probably solve your error, but just want to make an attempt to optimize your code.
That array, loop, etc. is unnecessary, ask your db to do that stuff and get the top posts. Fetching all posts and looping over it multiple times...nay, try the following, hopefully this is what you are looking for..
#top_posts = Post.order('view_count desc').limit(5)
That's it, your view needs no change and will work as expected.
Try:
#top_posts << post
instead of:
#top_posts[counts.max(5).index(n)] = post
You don't need to set the array index.

Array of hashes where hash is returned by a function in jbuilder

I have a PORO TutorProfileHandler that has a function json that returns a hash.
class TutorProfileHandler
def initialize(opts)
#profile = opts[:tutor_profile]
end
def json
tutor = #profile.tutor
return {
id: tutor.id,
first_name: tutor.first_name,
last_name: tutor.last_name.first + '.',
school: #profile.school,
avatar: #profile.avatar.url,
bio: #profile.bio,
academic_level: #profile.academic_level,
headline: #profile.headline,
major: #profile.major,
rate: #profile.rate,
rating: #profile.rating,
courses: JSON.parse(#profile.courses),
video_url: #profile.video_url
}
end
end
In my index_tutor_profiles.json.jbuilder, I would like to generate
{
tutor_profile: [{id: 1, ...}, {id: 2, ...}, ...],
tutor_sum: 20
}
However when I do this
json.tutor_profiles (#tutor_profiles) do |profile|
TutorProfileHandler.new({tutor_profile: profile}).json
end
json.tutor_sum #tutor_sum
It gives me an empty array for tutor_profiles.
However if I move everything from TutorProfileHandler.json to the jbuilder file, it works. How do I explicitly include the hash returned by TutorProfileHandler.json in the jbuilder array?
Note: This returns an array, but it creates a new key-value pair array:
json.tutor_profiles json.array(#tutor_profiles) do |profile|
TutorProfileHandler.new({tutor_profile: profile}).json
end
Result:
{
array: [{id: 1, ...}, {id: 2, ...}, ...],
tutor_profile: [],
tutor_sum: 20
}
There is a ugly approach:
json.tutor_profiles #tutor_profiles do |profile|
tmp_json = TutorProfileHandler.new({tutor_profile: profile}).json
json.(tmp_json, *(tmp_json.keys))
end
I think the best practise is directly nesting inside model. You can get more information from the its github page.

searchkick advanced search not working

class Product < ActiveRecord::Base
belongs_to :city
has_and_belongs_to_many :categories
before_destroy { categories.clear }
searchkick locations: ["location"]
def search_data
{
istatus: i_status,
name: name,
price: price,
city_id: city_id,
value: value,
discount: discount,
expiry_date: expiry_date,
created_at: created_at,
products_sold: products_sold,
city: city.name,
deal_type: deal_type,
country: city.country.name,
category_id: categories.map(&:id),
location: [latitude, longitude]
}
end
def self.apply_filters(request)
# #product = Product.search "Tex-Mex", limit:10 #=>this works
#product = Product.search body: {match: {name: "Tex-Mex"}},limit: 10 #=>does not work, the limit part work
end
end
when i use advanced search using body.. it does not return the desired results although the limit:10 part us working as it does return 10 results only
I believe there is some missing information in the documentation.
Here's a reference to a body query that works based on the tests written in SearchKick:
https://github.com/ankane/searchkick/blob/c8f8dc65df2e85b97ea508e14ded299bb8111942/test/index_test.rb#L47
For advanced search to work, the way it should be written is:
#product = Product.search body: { query: { match: {name: "Tex-Mex"}}},limit: 10
You need a query key following the body.
// conditions = {}
query = Product.search params[:query], execute: false, where : conditions
query.body[:query] = { match: {name: "Tex-Mex"} }
query.body[:size] = 10
query.execute
You would need to build your query using the Elasticsearch DSL. Specifically, using size and match.
Product.search body: { query: { match: {name: "Tex-Mex"} }, size: 10 }
When using Advanced search, Searchkick ignores parameters outside the body hash. While the body hash allows you to use the full ES DSL.

Grouping by attribute of associated objects

class Event < ActiveRecord::Base
has_many :meetings
end
class Meeting < ActiveRecord::Base
belongs_to :event
end
How to write mysql query to search all events group_by meeting DATE(start_at)?
Event.inludes(:meetings).group ...
As a result I want to get a Hash:
{"2014-01-24"=>[#<Event id: , title: "First", created_at: "2014-01-24 16:02:52", updated_at: "2014-01-24 16:02:52">, #<Event id: 2, title: "Second", created_at: "2014-01-24 16:02:52", updated_at: "2014-01-24 16:02:52">], "2013-01-29"=>[#<Event id: 3, title: "Third", created_at: "2013-01-29 05:30:40", updated_at: "2014-01-29 05:30:40">], ...]}
P.S: I am using PostgreSQL
Now I get it by this way:
hash = {}
Meeting.where("extract(month from start_at) = ?", Date.today.month).pluck('DATE(start_at)').uniq.each do |date|
hash[date] = Event.includes(:meetings).where("DATE(meetings.start_at) = ?", date).references(:meetings)
end
But it produced so many queries to the database :(
Event.joins(:meetings).group('meetings.start_at') should do. But want you want is a group_by array method http://apidock.com/ruby/Enumerable/group_by so what you should do is
#events.group_by {|e| e.meeting.start_date}
In case of many to many you should be better off with
result = Hash.new
Meeting.include(:events).each {|m| result[m.start_at]||=[]; result[m.start_at] << m.events}
and with one liner you could
Meeting.includes(:events).inject(Hash.new) do |result, m|
result[m.start_at]||=[]
result[m.start_at] << w.events
result
end
This code should execute two database calls i think

Resources