Самый быстрый способ вернуть список записей в зависимости от многих отношений «многие ко многим» - PullRequest
0 голосов
/ 07 октября 2018

Я разрабатываю API в Rails, в котором существуют таблицы users и messages.Также users имеют пол (gender_id), принадлежат к стране (country_id), а также имеют гражданский статус (civil_status_id), а messages создаются admins.

Итак, до сих пор у меня есть эта модель.

enter image description here

Теперь мне нужно разработать следующее требование

Администратор должен иметь возможность создавать сообщение с адресом users в зависимости от его атрибутов (страна, пол или гражданский статус).Кроме того, администратор должен иметь возможность объявлять сообщение как глобальное сообщение, в этом случае «all» users должно его получать, но исключения также должны быть разрешены.Например, в случае, когда администратор хочет отправить сообщение пользователям из всех стран, кроме людей из России и Китая.

Дело в том, что я не являюсь экспертом по Rails / SQL, но яЯ хочу сделать это эффективно, чтобы, если завтра у приложения будет десять тысяч или сто тысяч пользователей, сервер быстро откликнется.

Поэтому я подумал о следующем

Первое создание3 отношения «многие ко многим» (countries_messages, genders_messages и civil_statuses_messages).Записи этих таблиц представляют отношения между messages и countries, civil_statuses и genders.

Затем создайте форму, где администратор может создать сообщение, где с помощью несколькихвыбирая поля, он должен иметь возможность выбирать атрибуты пользователей, с которыми он хочет связаться.Форма для создания сообщения также должна иметь флажок, чтобы определить, является ли сообщение глобальным, если оно помечено, я бы посчитал, что выбранные страны, полы и гражданские статусы будут категориями, которые администратор хочет исключить, т. Е. Если администраторЧтобы отправить сообщение всем людям в системе, кроме людей из Канады, он должен отметить глобальную опцию и выбрать страну Канада в поле выбора (очевидно, это будет указано в представлении).

Теперь у меня есть эта модель.

enter image description here

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

Метод 1

Когда администратор указывает, что сообщение является глобальным, за исключением сообщений из страны с идентификатором 3, тогда я могу добавить к countries_messages записи типа (country_id: 1,message_id: 2), (country_id: 2, message_id: 2), (country_id: 4, message_id: 2), ... и т. д., т. е. формирование отношения с каждой страной, кромеept the country with id 2.

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

global_messages = Message.where(global: true).ids

country_messages = current_user.country.messages.ids
gender_messages = current_user.gender.messages.ids
civil_status_messages = current_user.current_status.messages.ids

@messages = Message.find(global_messages + country_messages + gender_messages + civil_status_messages)

Метод 2

Другим способом может быть формированиесвязь этого сообщения с исключенной страной, т.е. если я делаю сообщение исключительно для людей из страны с идентификатором 2, тогда я должен добавить запись (country_id: 2, message_id: 2) в countries_messages, но в противном случае, если яотправил сообщение в каждую страну, кроме страны с идентификатором 2, тогда я должен также добавить запись (country_id: 2, message_id: 2) в countries_messages.

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

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

global_messages = Message.where(global: true).ids

country_messages = current_user.country.messages
gender_messages = current_user.gender.messages
civil_status_messages = current_user.current_status.messages

excluded_country_messages_ids = country_messages.where(global: true).ids
excluded_gender_messages_ids = gender_messages.where(global: true).ids
excluded_civil_status_messages_ids = civil_status_messages.where(global: true).ids

@messages = Message.find(global_messages + country_messages + gender_messages + civil_status_messages - excluded_country_messages_ids - excluded_gender_messages_ids - excluded_civil_status_messages_ids)

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

1 Ответ

0 голосов
/ 07 октября 2018

В зависимости от выбора базы данных, вы можете рассмотреть вопрос о сохранении «атрибутов» сообщения (страна, пол, ...) в столбце jsonb таблицы сообщений.Он также может включать атрибут user_ids для упрощения работы.Запросы могут показаться немного забавными, но вы можете многое перенести в области видимости, чтобы прояснить ситуацию в своем коде и даже добавить индексы, чтобы ускорить процесс.

Вот отличная статья об использовании jsonb синдексы в Rails с postgresql .

Другая альтернатива, которую вы можете сделать, - создать таблицу соединений UserMessage с полиморфной ссылкой, которая может связывать различные атрибуты с сообщением и пользователем:

class UserMessage < ApplicationRecord
  belongs_to :user
  belongs_to :message
  belongs_to :messageable_type # e.g. "Country"
  belongs_to :messageable_id # e.g. some Country id
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...