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

Предположим, у меня есть таблица как таковая

    id user_id  value
     1   1       A
     2   1        A
     3   1       A
     4   1       A
     5   1       A
     6   1       A
     7   2       B
     8   2       B
     9   3       C

Как видите, в этой таблице много дубликатов. Для каждого дубликата я хочу иметь возможность удалить все, кроме одного, так что у меня все еще остается одна запись для каждой дублированной записи. Например, для дубликатов записей с user_id = 1 и value = A я хочу иметь возможность удалить все, кроме одного, чтобы у меня осталась одна запись со значениями user_id = 1 и value = A

1 Ответ

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

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

Другой вариант - перехватить вызов метода создания ActiveRecord для предотвращения дублирования:

class Example < ApplicationRecord
  def self.create( attributes = nil, &block )
    attributes.each {|attr| self.create(attr, &block) } if attributes.is_a? Array
    return if find_by attributes
    super attributes, &block
  end
end

Основная идея здесь в том, чтобы прервать работу, если вы уже видите запись с такими же значениями атрибутов в базе данных ... но затем позволить ActiveRecord продолжать выполнять всю тяжелую работу, вызывая ее с помощью super.

Если есть ситуация, когда по какой-то причине вы не можете осуществлять контроль над базой данных, чтобы предотвратить ввод дубликатов, вы можете попробовать подход, при котором вы создаете метод класса для периодической очистки дубликатов из системы.

Вот пример метода, который будет перебирать весь набор записей и использовать хеш для отслеживания того, видел ли он значения раньше, удаляя их, если это так:

class Example < ApplicationRecord
  def self.dedup
    distinct = {}
    all.each do |row|
      if distinct[row.user_id] && distinct[row.user_id] == row.value
        row.delete
      else
        distinct[row.user_id] = row.value
      end
    end
  end
end

Затем вы можете назвать это так: Example.dedup всякий раз, когда вы хотите удалить дубликаты записей.

Для тех, кто хочет следовать дома, вы можете использовать следующую миграцию:

rails g model example user_id:integer value:string

и исходный файл:

examples = Example.create([
  {user_id: 1, value: 'A'},
  {user_id: 1, value: 'A'},
  {user_id: 1, value: 'A'},
  {user_id: 1, value: 'A'},
  {user_id: 1, value: 'A'},
  {user_id: 1, value: 'A'},
  {user_id: 1, value: 'A'},
  {user_id: 2, value: 'B'},
  {user_id: 2, value: 'B'},
  {user_id: 3, value: 'C'},
])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...