Рельсы выбирают по количеству связанных записей - PullRequest
0 голосов
/ 21 июня 2019

У меня есть следующие модели в приложении rails:

class Student < ApplicationRecord
  has_many :tickets, dependent: :destroy
  has_and_belongs_to_many :articles, dependent: :destroy

class Article < ApplicationRecord
  has_and_belongs_to_many :students, dependent: :destroy

class Ticket < ApplicationRecord
  belongs_to :student, touch: true

Мне нужно извлечь всех Студентов, у которых меньше статей, и мне нужно извлечь всех Студентов, у которых последний билет называется «Нечто».

Все, что я до сих пор пробовал, занимает много времени.Я попытался составить карту и пройтись по всем студентам.Но я думаю, что мне нужен объединенный запрос.Я ищу наиболее эффективный способ сделать это, поскольку база данных, с которой я работаю, достаточно велика.

Ответы [ 3 ]

2 голосов
/ 21 июня 2019

ответьте на первый ответ на вопрос @ MCI. Но фильтр / select / find_all или что-то еще (хотя я не слышал о методе фильтра в ruby) через запись ученика берет n запросов, где n - количество записей ученика (называемое запросом n + 1).

studs = Student.find_by_sql(%{select tmp.id from (
  select student_id as id from tickets where name='Something' order by tickets.created_at desc
) tmp group by tmp.id})
2 голосов
/ 21 июня 2019

Вы спросили "I need to extract all Students who has less than articles". Я предполагаю, что вы имели в виду "I need to extract all Students who have less than X articles". В этом случае вы хотите group и having https://guides.rubyonrails.org/active_record_querying.html#group.

Например, Article.group(:student_id).having('count(articles.id) > X').pluck(:student_id).

Чтобы ответить на второй вопрос, вы можете использовать стремительную загрузку https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations, чтобы ускорить ваш код.

result = students.filter do |student|
  students.tickets.last.name == 'Something'
end
1 голос
/ 21 июня 2019

Здесь ассоциация HABTM, поэтому нижеприведенный запрос должен работать

x = 10
Student.joins(:articles).group("articles_students.student_id").having("count(articles.id) < ?",x)
...