komron️
Всем привет. Есть вопрос на счёт дизайна моей базы данных в монге. Если есть мысли, пишите.
komron️
Вообщем я пишу бота для того чтобы тянул новости из RSS фидов. Есть две коллекции - «user» и «rss». В user’e находятся настройки (там конечный автомат, язык), а в rss находятся информация с фидов (ссылка, имя ресурса). Объединяются эти оба документа тем фактом то что у user’a есть лист в котором object_id фидов к которым он подписаны, а у rss есть лист user_id юзеров подписчиков которые берут новости с него (чтобы не обновлять одну и ту же вещь дважды) Теперь, надо имплементировать текстовые фильтры, но они кастомные для каждого юзера. Куда мне их добавлять? в user? rss? У меня будет отдельный модуль который будет проходится по документам в коллекции rss и отправлять новости тем юзерам user_id которых есть в листе подписчиков, но надо добавить функционал где он будет фильтровать то что юзеры не хотят видеть (слова, реклама и тд). Если я добавлю эту инфу в документы user’a, тогда получается что мой модуль должен будет делать слишком много запросов в дб. так что я не знаю...
Nickolay
Вообщем я пишу бота для того чтобы тянул новости из RSS фидов. Есть две коллекции - «user» и «rss». В user’e находятся настройки (там конечный автомат, язык), а в rss находятся информация с фидов (ссылка, имя ресурса). Объединяются эти оба документа тем фактом то что у user’a есть лист в котором object_id фидов к которым он подписаны, а у rss есть лист user_id юзеров подписчиков которые берут новости с него (чтобы не обновлять одну и ту же вещь дважды) Теперь, надо имплементировать текстовые фильтры, но они кастомные для каждого юзера. Куда мне их добавлять? в user? rss? У меня будет отдельный модуль который будет проходится по документам в коллекции rss и отправлять новости тем юзерам user_id которых есть в листе подписчиков, но надо добавить функционал где он будет фильтровать то что юзеры не хотят видеть (слова, реклама и тд). Если я добавлю эту инфу в документы user’a, тогда получается что мой модуль должен будет делать слишком много запросов в дб. так что я не знаю...
Ты неправильно определил отношения юзера к ленте. Правильным путем было бы создание отдельной коллекции с маппингом idшников друг на друга
Nickolay
Если у одного юзера может быть несколько фильтров, то и их бы бросил отдельно и таким же способом связал
Nickolay
В книге mongo in action хорошо расписано про отношения сущностей в базе, чтиво об отношениях на 15 минут
Nickolay
да
Nickolay
лол тогда зачем мне вообще монга? я думал так не принято делать с document-based дб
так зачем она тебе? 🙂 Работа с листами медленная, ты можешь оставить как придумал, но потом будешь переделывать
Nickolay
при текущем дизайне ты будешь делать много запросов с поиском по листам, как ты собираешься индексировать это?
Nickolay
еще глубже объяснено в вышеупомянутой книге
yopp
Вообщем я пишу бота для того чтобы тянул новости из RSS фидов. Есть две коллекции - «user» и «rss». В user’e находятся настройки (там конечный автомат, язык), а в rss находятся информация с фидов (ссылка, имя ресурса). Объединяются эти оба документа тем фактом то что у user’a есть лист в котором object_id фидов к которым он подписаны, а у rss есть лист user_id юзеров подписчиков которые берут новости с него (чтобы не обновлять одну и ту же вещь дважды) Теперь, надо имплементировать текстовые фильтры, но они кастомные для каждого юзера. Куда мне их добавлять? в user? rss? У меня будет отдельный модуль который будет проходится по документам в коллекции rss и отправлять новости тем юзерам user_id которых есть в листе подписчиков, но надо добавить функционал где он будет фильтровать то что юзеры не хотят видеть (слова, реклама и тд). Если я добавлю эту инфу в документы user’a, тогда получается что мой модуль должен будет делать слишком много запросов в дб. так что я не знаю...
у вас пример many-to-many отношений с метаданными
yopp
тут есть много вариантов
yopp
самый простой сделать понятие «подписка», которая будет включать в себя три параметра: пользователь, фид, фильтры
yopp
да
yopp
и в зависимости от того, как вы хотите доставлять пользователям обновления, у вас есть разные варианты
yopp
но в любом случае, если у вас будут текстовые фильтры по всему содержимому rss записи, простого решения не будет
komron️
и в зависимости от того, как вы хотите доставлять пользователям обновления, у вас есть разные варианты
просто удобство того что я делаю на данный момент (без фильтров) это то что когда время начать доставлять новости юзерам - я могу просто пройтись по каждому документу в базе, и доставлять идентичные новости всем пользователям-подписчикам
yopp
у вас доставка в каком виде происходит?
komron️
у вас доставка в каком виде происходит?
сообщение - это бот в телеграм.
yopp
ага
yopp
т.е. у вас задача при появлении нового фида, определить каким пользователям надо отправить сообщение
komron️
но теперь надо учитывать фильтры
yopp
фильтры у пользователя глобальные или на каждую подписку?
komron️
на самом деле тут не только rss, но еще и твиттер аккаунты, и т.д.
komron️
komron️
yopp
ага
yopp
я бы вынес подписки в отдельную коллекцию
yopp
и там бы хранил метаданные
komron️
просто все подписки подряд?
yopp
обычно у пользователя меньше подписок, чем у подписок пользователей, а значит в ней стоит групировать подписки по пользователям
yopp
т.е. по отдельному документу на пользователя и туда положить фильтры
yopp
если так-же сделать user_id: …; то в этом случае можно будет легко решить проблему, когда у пользователя очень много подписок и они не влазят в один документ
komron️
а для существующих коллекций надо что-то менять?
komron️
опять таки самым затратным будет обновление ресурсов rss, так что я не очень хочу чтоб я один тот же ресурс брал дважды для отправки пользователю
yopp
что-то в духе { _id: ObjectId, user_id: ..., filters: [...], feed_ids: [ObjectId, ObjectId], count: <feeds.count> } дальше индекс по feed_ids и когда вы добавляете новую запись в ленту, то вы в один запрос можете вытащить всех подписанных пользователей. Плюс, в теории, можно сразу отрбасывать пользователей по значению filters. Но тут надо стеммер с обоих сторон. Сделать частотный анализ статьи, выбрать N самых частых слов, получить для всех слов исходные словоформы и добавит их как условие в запрос. А при добавлении нового фильтра, в отдельное поле добавлять словоформы фильтров.
yopp
Так можно отбросить часть пользователей сразу, но кроме безобидных ложно-отрицательных срабатываний, могут быть очень обидные ложно-положительные
yopp
но это всё будет зависеть от того как вы хотите фильтровать в принципе
yopp
если по точному совпадению, то можно без словоформ обойтись
yopp
(хотя наверное частотный анализ лучше сразу по словоформам делать)
komron️
так получается поле subscribed в коллекции rss стоит сбросить?
Nickolay
Почему не хранить filter, user и feed в разных коллекциях? это же будет работать намного быстрее. Я год назад переписывал как раз похожий дизайн монги и много времени делалась выборка с листами
Nickolay
и как я понимаю ObjectId в поле feed_ids тут это reference на документы rss?
reference это драйверозависимая штука, фактически может быть много запросов на вытягивание данных из соседних коллекций, самое простое - сделать отдельные коллекции для определения связей, да так будет по два запроса, но два простых и быстрых
komron️
окей, ну тогда при доставке новостей, я буду проходить через каждый документ в rss, и по каждому подписчику буду вытягивать фильтры?
yopp
да
yopp
выбирая между «хранить фильтры у пользователя» и «хранить список подписчиков в фидах вместе с фильтрами», я предлагаю выбрать «завести третью коллекцию с подписками и фильтрами». это более гибкое решение
yopp
16 мегабайт не так много как кажется
komron️
все стало гораздо понятней 👍
yopp
если сразу использовать паттерн бакет для подписок, и ограничить один документ сотней-другой, то проблем особых не будет
yopp
https://www.mongodb.com/blog/post/building-with-patterns-the-bucket-pattern
komron️
кстати о третей коллекции, я правильно понимаю что оно будет более короткой версией коллекции users - но теперь с фильтрами и подписками?
yopp
https://www.mongodb.com/blog/post/paging-with-the-bucket-pattern--part-1
yopp
причём я рекомендую фильтры хранить ещё и у пользователя
yopp
т.е. source of truth это users, а в подписках кешировать значение и обновлять его вместе с обновлением у пользователя
komron️
окей, спасибо большое за вашу помощь!
Алексей
У монги много применений
Разве среди них есть вариант "использовать монгу как реляционную бд"? Можно какой-то Профит получить?
Nick
Разве среди них есть вариант "использовать монгу как реляционную бд"? Можно какой-то Профит получить?
Конечно можно, если у вас не девятиэтажные скульники с парой дестков джойнов. Пару тройку лукапов вполне нормально использовать. И да достаточно определьть потребности запросов и под них делать структуру, не ради хранения бизнесс сущностей
Dmitriy
Разве среди них есть вариант "использовать монгу как реляционную бд"? Можно какой-то Профит получить?
имхо основной профит от монги - это реплика и шардирование из коробки, без плясок с бубном как на постгре или мускуле. но тут конечно все сильно от задачи зависит
Dmitriy
Добрый день, господа и дамы. Подскажите, можно ли в запросе приводить один тип к другому? Есть задача взять данные по времени, но время в поле документа сохраненно как строка.
Bohdan
https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromString/
Bohdan
может быть это то что тебе нужно
Dmitriy
Добрый день, господа и дамы. Подскажите, можно ли в запросе приводить один тип к другому? Есть задача взять данные по времени, но время в поле документа сохраненно как строка.
если данных не много, то сделай один раз миграцию, чтобы конвертировать строку в временную метку и из приложения писать нормальную временную метку. сильно сэкономишь на выборках и времени и нервов
Aʟᴇx
Разве среди них есть вариант "использовать монгу как реляционную бд"? Можно какой-то Профит получить?
Поскольку это очень философская и спорная тема, то давай я скажу свое мнение. Нет такого варианта как "использовать монгу как реляционную субд". Есть такой вариант как "использовать нормализованную модель базы данных для приложения по управлению контентом". И это в монге можно делать и делать хорошо.
yopp
более того, под «реляционными базами» обычно понимаются табличные хранилища с гарантиями целостности ссылок между записями. но в реальности такие хранилища очень плохо работают с отношениями, потому ссылки между записями в таблицах позволяют эффективно моделировать только очень небольшой срез систем отношений. а настоящей «реляционной базой» будет современное графовое хранилище, в котором отношения являются строительным блоком. например neo4j.
Anonymous
Привет. Распарсил длинный .csv файл в массив объектов. Существует метод для отправки в Mongo всего массива с последующим сохранением вместо пробегания по массиву и сохранения объектов в БД поштучно?