Методы ActiveRecord для поддержания чистоты баз данных


Загрязненные базы данных снижают производительность.

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

Решение наивно простое: не вводите в наш набор данных противоречивые записи.

Хотя ограничения и параметры каждого набора данных различны, общий процесс и применение этого решения одинаковы.

  1. Определите, какие параметры будут использоваться для поиска существующих записей в наборе данных вашей модели.
  2. Уникально идентифицируйте каждую запись при отправке записи/записей.
  3. Обработать все ответы на запросы к набору данных.

Достаточно просто, верно? К счастью, ActiveRecord предлагает несколько методов поиска. Эти методы позволяют нам определить, существует ли конфликтующая запись, прежде чем вводить новую запись в нашу базу данных.

Давайте рассмотрим, как поддерживать стабильную и чистую базу данных на практических примерах.

Queue Wag n’ Walk — планировщик расписания, предназначенный для выгула собак. Есть несколько различных головных болей, которые могут возникнуть из-за загрязнения базы данных; давайте определим различные записи, которые могут повредить нашу таблицу встреч.

Этот пример требует базового понимания гема ActiveRecord, ассоциаций таблиц и таблиц SQL.

1. Определение полезных параметров

Каждая запланированная встреча имеет 4 различных пользовательских входа: дата/время, собака, выгульщик (сотрудник) и продолжительность прогулки. Следует выделить несколько потенциальных конфликтов при планировании:

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

Первый метод, который следует рассмотреть, это метод find_or_create_by.
Этот метод либо находит первую запись с заданными атрибутами, либо создает новую запись, если таковая не найдена. Этот метод полезен, когда мы ищем точную запись, или когда наш набор данных прост.

Appointment.find_or_create_by({ 
employee_id: params[:employee_id] , 
start: params[:start]})
Войти в полноэкранный режим Выход из полноэкранного режима

Если в нашей таблице назначений не найдена запись с указанным идентификатором сотрудника и датой/временем начала приема, то вводится новая запись.

Если мы попытаемся запланировать прием, в то время как существующий прием находится в процессе, наш метод find_or_create_by не заметит этого и внесет в расписание конфликтующую запись для нашего ходока.

Цепочка методов

Второй метод, который следует рассмотреть, — это комбинация нескольких методов, известная как цепочка методов. С помощью цепочки методов мы можем применять несколько условий для проверки и поиска записей в нашей базе данных.

.где Метод

exist = Appointment.where({
      start: params[:start] , 
      dog_id: params[:dog_id]
      })
Войти в полноэкранный режим Выйти из полноэкранного режима

Метод .where выбирает все записи, которые соответствуют атрибутам, переданным в метод. В данном случае exist будет равен всем встречам, время начала которых совпадает с указанным временем начала, а идентификатор собаки совпадает с идентификатором собаки.

.или Метод

 exist = Appointment.where({
      start: params[:start] , 
      dog_id: params[:dog_id]
      }).or(Appointment.where({start: params[:start] , 
            employee_id: params[:employee_id]}))
Войти в полноэкранный режим Выйти из полноэкранного режима

Используйте метод .or, чтобы добавить второе условие к запросу. В данном случае мы ищем любую встречу, соответствующую указанному времени начала и идентификатору собаки, или любую встречу, соответствующую указанному времени начала и идентификатору сотрудника.

Метод .find_all

appt_in_progress_dogs = Appointment.all
.find_all {|a| a[:dog_id] == params[:dog_id]}
Вход в полноэкранный режим Выход из полноэкранного режима

Метод find_all возвращает массив, содержащий выбранные записи, для которых заданный блок возвращает истинное значение. В данном случае мы находим все записи из таблицы Appointments, чей идентификатор собаки совпадает с указанным идентификатором собаки.

.between? Метод

appt_in_progress_dogs = Appointment.all
.find_all {|a| a[:dog_id] == params[:dog_id]}
.find_all {|a| params[:start].between?(a[:start] , a[:end])}
Войти в полноэкранный режим Выйти из полноэкранного режима

Метод between возвращает значение true или false. Он определяет, находится ли значение между заданным минимумом или максимумом. В данном случае мы хотим найти все записи с идентификатором собаки, совпадающим с заданным идентификатором собаки. Затем из этих записей мы хотим найти все случаи, когда новая встреча начинается в то время, когда существующая встреча для данной собаки находится в процессе.
Другими словами, мы не хотим назначать прогулку для собаки, если она находится в середине прогулки. Тот же случай применим для любого выгульщика (сотрудника).

Метод .find_in_batches

Appointment.find_in_batches(batch_size: 1000) do |a|
       a.find_by({start: params[:start]}) 
      end
Вход в полноэкранный режим Выйти из полноэкранного режима

Метод find_in_batches полезен при работе с большими наборами данных. Если указать размер партии, то этот метод будет запрашивать только указанный размер партии за один раз. Этот метод снижает некоторые проблемы производительности, возникающие при работе с большими наборами данных.

Мы можем быть более целенаправленными и конкретными в отношении типов записей, которые мы хотим найти с помощью цепочки методов.

2. Уникальная идентификация записей

Этот ответ довольно прост при использовании Active Record. При использовании Active Record Migrations столбец первичного ключа создается автоматически, и каждой записи, внесенной в нашу таблицу, присваивается уникальный идентификатор.

3. Обработка ответов на запросы

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

Утверждение IF

if !exist.exists? &&[*appt_in_progress_dogs,*appt_in_progress_walkers].length < 1
Войти в полноэкранный режим Выйти из полноэкранного режима

Оператор IF в нашем методе POST использует запросы, которые мы выполнили. Если новый запрос на прием точно не совпадает ни с одной существующей записью, то он проходит первое условие в операторе IF. Метод .exists? возвращает true или false. В этом случае, если записи не существует, мы переходим к проверке второго условия.

Второе условие оператора IF использует оператор splat (*), который функционирует аналогично оператору spread (…) в Javascript (ES6). Если для указанной собаки или выгульщика не найдено ни одной незавершенной встречи, то длина нашего массива будет равна нулю.

Если оба условия выполнены, то будет создано новое назначение с предоставленными атрибутами, отправленными нашим фронт-эндом, а наш ответ будет отправлен в виде объекта JSON.

Утверждение Else
Если одно из условий возвращает false, то наш бэкэнд отправит ответ с сообщением об ошибке в виде объекта JSON. Некоторые ошибки могут быть сложнее, чем другие, и поэтому вы можете настроить несколько условий для разных ошибок.

   fetch(`http://localhost:3005/appointments` , {
      method : 'POST' ,
      headers: { "Content-Type" : 'application/json'} ,
      body : JSON.stringify(newAppointment)
    })
      .then(r => r.json())
      .then((appointment) => {
        if(Object.keys(appointment).length === 1) {
          alert(appointment.error)
        } else {
          setAppointments([...appointments , appointment])
          alert(`Appointment for ${newDate} at ${time} has been scheduled`)
        }
      })
Вход в полноэкранный режим Выход из полноэкранного режима

Учитывая ответ, полученный от нашего первоначального POST-запроса, мы оповещаем пользователя либо об успешно назначенной встрече, либо об ошибке, которую мы отправили из бэкенда.

Те же запросы и условия могут быть применены и к запросу PATCH. Нам также нужно проверить, вызовет ли обновление существующей встречи такое же загрязнение, как и наш POST-запрос.

В заключение

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

Ресурсы

Как работать с дублирующимися записями
CS: Дублирующиеся записи
Что такое очистка данных
Документы по Ruby on Rails
Документы по миграции активных записей

Оцените статью
devanswers.ru
Добавить комментарий