There is a table of addresses

Address model: belongs_to :service belongs_to :district has_many :providers, dependent: :destroy has_many :comments, dependent: :destroy has_many :jobs, through: :providers 

Each address has comments (reviews) with the stars field (rating). In the address model, I made a method:

 Address.rb def self.find_by_test(params) addresses = Address.where(services:{active: true}).joins(:service).joins(:district => :city).joins(:district).joins(:jobs).includes(:addresses_car_models, :car_models).joins(:comments) addresses = addresses.where(:cities => { :id => params[:city_id] }) if params[:city_id] addresses = addresses.where(:districts => { :slug => params[:district_slug] }) if params[:district_slug] addresses = addresses.where(:jobs => { :slug => params[:job_slug]}) if params[:job_slug] addresses = addresses.where(:car_models => { :slug => params[:car_model] }) if params[:car_model] addresses_with_rating = [] addresses = addresses.distinct addresses.map.with_index do |addr,i| rating = addresses.select('comments.stars').where(comments:{confirmed: true, address_id: addr.id}).distinct.average('comments.stars') rating = 0.0 unless rating provider = addr.providers.joins(:job).where(:jobs => {:slug => params[:job_slug]}).first if params[:job_slug] last_record = addr.comments.where(address_id: addr.id).order(:updated_at => :asc).last last_record = (last_record || addr).updated_at comments_count = addr.comments.count addresses_with_rating[i] = {location: addr.location, latitude: addr.latitude, longitude: addr.longitude, days: addr.days, start_time: addr.start_time, end_time: addr.end_time, around_the_clock: addr.around_the_clock, id: addr.id, rating: rating.to_f, online: addr.service.online, name: addr.service.name, service_id: addr.service.id, phone: addr.phone, avatar: addr.service.avatar, description: addr.service.description, comments_count: comments_count, slug: addr.service.slug, provider:provider, last_subscribed: last_record} end addresses_with_rating = addresses_with_rating.sort_by { |k| k[:rating]}.reverse if params[:start] && params[:finish] addresses_with_rating = addresses_with_rating[params[:start]..params[:finish]] else addresses_with_rating end end 

In the controller, I call it like this:

 @results = Address.find_by_test({ :city_id => params[:city].id, :district_slug => params[:district], :job_slug => params[:id], :car_model => params[:model] }) @services_count = @results.length @results = @results[0..1] 

There is also a method:

 def take @comments_count = Array.new @results = Address.find_by_test({ :city_id => params[:city].id, :district_slug => params[:district], :job_slug => params[:id], :car_model => params[:model], :start => params[:start].to_i, :finish => params[:finish].to_i }) cookies[:start] = cookies[:start].to_i + 2 cookies[:finish] = cookies[:finish].to_i + 2 end 

which i call in take.js.erb

 $(".search_results").append("<%= escape_javascript(render partial: 'list') %>"); $(".search_results").append("<%= escape_javascript link_to "Показать еще", list_path(:start => cookies[:start], finish: cookies[:finish]), :remote => true, class: 'btn btn-success more' %>"); 

Obviously with at least some large number of records and users, this will put a heavy load on the server. How to do without an array to be able to sort the addresses according to the average rating in the community? Solutions with will_paginate are not suitable, because This gem conflicts with others in the project.

  • Write a rating calculation in a SQL query except that. - D-side
  • so I don’t understand how to write it so that in the query in which there are N addresses, each one should calculate the rating in one sql query, only a cycle comes to mind - Tiazar
  • I looked at how addresses compiled ... I don’t undertake to guess how much SQL it generates by itself, almost all associations are attached there, and at odds with each other ... Do you do a search in the manner of those found in online stores? This is usually solved by a separate search solution like Sphinx or ElasticSearch. This is so note. I am sure that it is also possible with DB tools, but is it worth it? .-. - D-side

1 answer 1

In the end, it was done this way: a field with a rating was added to the address table; when the moderator confirms the feedback, ratings are collected from suitable reviews and the value is written to a new field. In this case, a complex query is not needed.