В Rails лучший способ хранения нескольких логических атрибутов в модели?

У меня есть модель House, которая имеет много логических атрибутов, таких как has_fireplace, has_basement, has_garage и т.д. House имеет около 30 таких логических атрибутов. Каков наилучший способ структурирования этой модели для эффективного хранения и поиска баз данных?

Я хотел бы, в конечном счете, искать все Houses, у которых есть камин и гараж, например.

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

Ответы

Ответ 1

Ваше "наивное" предположение верно: наиболее эффективным способом с точки зрения скорости и производительности является добавление столбца для каждого флага.

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

Ответ 2

Для этого много булевых элементов в одной модели вы можете использовать одно целое и побитовые операции для представления, хранения и извлечения значений. Например:

class Model < ActveRecord::Base
  HAS_FIREPLACE = (1 << 0)
  HAS_BASEMENT  = (1 << 1)
  HAS_GARAGE    = (1 << 2)

  ...
end

Затем некоторый атрибут model, называемый flags, будет установлен следующим образом:

flags |= HAS_FIREPLACE
flags |= (HAS_BASEMENT | HAS_GARAGE)

И протестирован следующим образом:

flags & HAS_FIREPLACE
flags & (HAS_BASEMENT | HAS_GARAGE)

который вы могли бы абстрагироваться от методов. Должно быть довольно эффективным во времени и пространстве как реализация

Ответ 3

Я предлагаю драгоценный камень flag_shih_tzu. Это помогает хранить много логических атрибутов в одном целочисленном столбце. Он дает вам имена областей для каждого атрибута и способ их объединения в качестве активных отношений записи.

Ответ 4

Здесь другое решение.

Вы можете создать модель HouseAttributes и настроить двустороннюю связь has_and_belongs_to_many

# house.rb
class House
  has_and_belongs_to_many :house_attributes
end

# house_attribute.rb
class HouseAttribute
  has_and_belongs_to_many :houses
end

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

Не забудьте настроить свою таблицу соединений в своей базе данных.

Ответ 5

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

Если вы не будете беспокоиться о производительности, я бы использовал реализацию, в которой каждое свойство представлено персонажем ( "a" = "гараж", "b" = "камин" и т.д.) и вы просто создаете строку, которая представляет все флаги, которые имеет запись. Основным преимуществом, которое это имеет в битполе, является то, что а) он легче отлаживать человека, и б) вам не нужно беспокоиться о размере ваших типов данных.

Если производительность является проблемой, тогда вам, скорее всего, придется продвигать их в поля первоклассного типа.

Ответ 6

Обычно я согласен с тем, что ваше наивное предположение верно.

Если количество булевых полей продолжает расти и расти (has_fusion_reactor?), вы можете также рассмотреть сериализацию массива флагов

# house.rb
class House
  serialize :flags
  …
end

# Setting flags
@house.flags = [:fireplace, :pool, :doghouse]
# Appending
@house.flags << :sauna
#Querying
@house.flags.has_key? :porch
#Searching
House.where "flags LIKE ?", "pool"

Ответ 7

Я думаю о чем-то вроде этого

У вас есть стол для дома (для подробной информации о доме)

У вас есть еще одна главная таблица под названием "Возможности" (которая имеет функции, такие как "камин", "подвал" и т.д.).

и у вас есть таблица соединения, такая как Houses_Features и у него есть house_id и feature_id

Таким образом, вы можете назначать функции для данного дома. не знаю, соответствует ли это вашим потребностям, но просто подумайте об этом: D

спасибо и приветствую

Sameera

Ответ 8

У вас всегда может быть столбец TEXT, в котором вы держите JSON (скажем, data), а затем ваши запросы могут использовать SQL LIKE.

Например: house.data # = > '{ "has_fireplace": true, "has_basement": false, "has_garage": true}'

Таким образом, поиск с использованием LIKE '%"has_fireplace":true%' вернет что-нибудь с камином.

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