Как получить значение, используя таблицу соединений с разными значениями? - PullRequest
0 голосов
/ 19 июня 2019

У меня есть товар, пользователь и модель product_click. В product_click у меня есть столбец count, в котором я веду запись, по которому пользователь нажимает какой продукт сколько раз.

Я тоже пробовал

Product.sort_by{ |r|  r.product_clicks.where(user_id: user.id).first.try(:count).to_i

, который дает желаемый результат, но создает много запросов при запуске.

product_click.rb

belongs_to :product
  belongs_to :user

product.rb

has_many :product_clicks, dependent: :destroy

user.rb

has_many :product_clicks, dependent: :destroy

Схема

create_table "product_clicks", force: :cascade do |t|
    t.bigint "product_id"
    t.bigint "user_id"
    t.bigint "count", default: 0
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

В контроллере

Product.left_outer_joins(:product_clicks).order("count DESC NULLS LAST")

Теперь я ищу что-то вроде этого.

Но здесь я не могу проверить, был ли счет какого конкретного пользователя. Если я добавлю

Product.left_outer_joins(:product_clicks).where(resource_clicks: { user_id: user.id }).order("count DESC NULLS LAST")

Затем он показывает продукт, который пользователь нажал, но не «ноль» (который я никогда не нажимал).

Я тоже пробовал это

Product.left_outer_joins(:product_clicks).where(product_clicks: { user_id: [user.id, nil] }).order("count DESC NULLS LAST")

но, давая мне все, на что я нажал, и все, на что еще никто не нажал. Если кто-то нажмет, что я не сделал, он не будет отображаться для меня.

1 Ответ

0 голосов
/ 20 июня 2019

Пока я думаю о других способах, одним прямым путем будет двухэтапное решение.

product_ids = ProductClick.where(user_id: user.id).order('count desc').pluck(:product_id)

products = Product.where(id: product_ids)

Это определенно улучшит ваше время и будет лучше, чем ваш запрос (то есть N + 1).

Использование предварительной загрузки

Product.includes(:product_clicks).where('product_clicks.user_id' => user.id).order('product_clicks.count desc')

Вышеприведенный запрос также должен привести к тому же результату, однако он может все равно выполнить два запроса.

Использовать пункт «есть» - рекомендуется

Product.includes(:product_clicks).having('product_clicks.user_id' => user.id).order('product_clicks.count desc')
...