В 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%'
вернет что-нибудь с камином.
Использование модельных отношений (например, модель для камина, подвала и гаража в дополнение к простому дому) было бы чрезвычайно громоздким в этом случае, поскольку у вас так много моделей.