Rails (Activerecord) - не может сделать запрос с объединениями и глобальной суммой без дубликатов - PullRequest
0 голосов
/ 31 января 2019

Я использую запрос с несколькими установленными пользователем фильтрами, чтобы показать список счетов в приложении Rails.Один из фильтров добавляет условие where для столбца отдельной таблицы, для которого необходимо двойное соединение, чтобы быть доступным (оценки через проекты -).

  scope :by_seller, lambda {|user_id|
    joins(project: :estimates)
    .where(estimates: {:user_id => user_id}) unless user_id.blank?
  }

Кроме того, я использую агрегат Railsметод "sum" для определения общего количества счетов, @ invoices.sum (: total_cache), где total_cache - это кэшированный столбец в базе данных, специально предназначенный для выполнения такого рода суммы быстрым способом.

@invoices.sum(:total_cache)

Моя проблема в том, что мне нужно двойное объединение для доступа к оценкам через проекты, и что каждый счет принадлежит проекту, НО проект может иметь много оценок, операция объединения приводит к дублированиюзаписей, так что в моей таблице «Счета-фактуры» много раз отображаются некоторые счета-фактуры (столько же, сколько и количество оценок, которые имеет проект).В результате получается таблица счетов с дублирующимися записями и неверное значение суммы, поскольку она суммирует некоторые итоговые суммы счета-фактуры N раз.

Поведение фильтрации просто отлично, поскольку я намерен фильтровать по пользователюкто сделал ЛЮБЫЕ оценки из проекта счета.Однако проблема заключается в том, что, когда я пытаюсь избежать дубликатов, добавляя группу ('invoices.id') - как я всегда разрешал такие ситуации - операция окончательного суммирования не возвращает общую сумму итоговых счетов., но сгруппированная сумма каждого из них (абсолютно бесполезная).

Единственный найденный мной обходной путь - включить предложение group и выполнить сумму в чистом рубиновом коде, рассматривая коллекцию как массив,ИМХО, что ужасно неэффективно, так как есть тонны счетов:

@invoices.map(&:total_cache).inject(0, &:+)

Есть ли способ, которым я могу получить уникальную коллекцию счетов ActiveRecord без дубликатов таким образом, чтобы я мог затем вызвать метод суммарной суммы и получитьобщее количество, подсчитанное Постгресом?

Конечно, если в моей базовой идее что-то не так, я полностью готов ее услышать!Это довольно сложный запрос (я упростил его ради вопроса здесь), и я уверен, что может быть много подходов!

Спасибо всем!

1 Ответ

0 голосов
/ 31 января 2019

Я не уверен, насколько "медленнее" или "быстрее" это, чем делать сумму в коде ruby.Но если вы хотите сохранить объект ActiveRecord::Relation, вы можете сделать что-то вроде ниже.Я воспроизвел вашу среду установки в локальном проекте Rails.

user = User.first

Invoice.where(
  id: Invoice.by_seller(user.id).select(:id)
).sum(:total_cache)

# (1.2 ms) SELECT SUM("invoices"."total_cache") FROM "invoices" WHERE "invoices"."id" IN (SELECT "invoices"."id" FROM "invoices" INNER JOIN "projects" ON "projects"."id" = "invoices"."project_id" INNER JOIN "estimates" ON "estimates"."project_id" = "projects"."id" WHERE "estimates"."user_id" = $1)  [["user_id", 1]]
# => 5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...