Как стать автором
Обновить

Комментарии 83

Язык запросов MongoDB также представлен в формате JSON документов.

Если вам повезло с ORM, то в ней и к SQL БД можно писать запросы в том же формате.


Если в какой-то момент вам нужно добавить новое поле "date_of_birth", вы просто начинаете работать с новыми JSON-документами с дополнительным полем. И все. Нет необходимости менять что-либо в схеме.

Ага, и на продакшене ваше приложение падает с NPE, потому что кто-то из старых юзеров открыл свой профиль, а в его джейсоне нет этого поля. Нетушки, надо либо менять модель/маппер, чтобы было хоть какое-то дефолтное значение, либо городить if'ы, либо, о ужас, все-таки писать миграцию.


Если вы правильно спроектируете коллекции, то сможете встраивать (embed) и дублировать данные в одной коллекции

Но нам ведь не надо задумываться над проектированием, т.к. у нас нет схемы БД!

НЛО прилетело и опубликовало эту надпись здесь

Ага, и на продакшене ваше приложение падает с NPE

Не ну кроме джавы еще есть языки, более удобные для Mongo/JSON :). А вообще, как Вы правильно заметили, Вам может повезти с ORM даже с джавой.

Ну не NPE, а какой-нибудь там "date_of_birth.toString is undefined", не в названии экскепшена суть:)

И все же я не вижу сложностей, данная проблема легко решается.

Решается очень легко: вы должны где-то записать, что какие-то поля могут отсутствовать. Это и есть схема. Просто она теперь не в БД, а на уровне приложения. Если в каком-нибудь postgres у вас будет написано `date_of_birth DATETIME NULL`, то теперь это будет написано в документации, в коде, в тестах или ещё где-то.

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

Ну то есть схема все таки есть? Но не в БД

Схема в том или ином виде всегда есть в приложении, иначе как работать с полями?

Конечно же она решается! Я указал аж 3 способа разной степени отвратности.

Но суть в том что новичкам это подают так, будто этой проблемы нет. А она есть.

Мой опыт с Монго:

1) каждый отдельный запрос выполняется относительно медленно (в сравнении с MySQL, например);

2) дублирование данных - это нормально;

3) надёжность не на высоте (не знаю насчёт последних версий.. может что-то улучшилось) - лучше не хранить в Монго критичные данные вообще;

Вывод: отлично подходит как доп. хранилище большого количества не очень важных данных (логов, например). Как основная и единственная СУБД - скорее нет.

А что там с надёжностью не то?


У нас используется один крупный опенсоурсный проект, там хранилище — Mongo, его выбрали «за нас» разработчики проекта. За 6 лет не было ни одной проблемы с надёжностью. Данные с самого начала дублируются на 3 инстанса MongoDB. Апгрейдили несколько раз версии, переезжали на WT, сейчас mongo 3.6, база 400Gb, всё нормально.

> За 6 лет не было ни одной проблемы ?

Либо это не правда, либо вы не знаете, либо не вы занимались апгрейдом. 6 лет назад монга была версии 2.6! Пройдитесь по всем версиям - раздел Compatibility Changes и known issues. Каждую версию присутствуют изменения обратно несовместимые! Мы довольно активно использовали aggregation framework - почти каждый апгрейд мы что-то ловили.

Пример со StackOverflow: предложенное решение работало в сентябре 2015 (версия 2.6 или 3.0), в 2018 уже нет (и вы даже не найдете этого в release notes, но это так) - т.е. после апгрейда у вас "некоторые" апдейты начинают работать не так как работали раньше без предупреждений... без ошибок... просто часть данных не обновляется... узнаете об этом в проде.

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

Казалось бы "не обновляйте" и живите себе спокойно и мы так и делали для одного из приложений которое просто работало себе спокойно на mongodb2.6... Но никакое облачное решение не вечно(MongoDb cloud) и заставляет мигрировать на новые версии, а мигрировав нам еще и драйвер надо обновить который несовместим с проектом... поддерживать стабильную работу mongodb2.6 на своих серверах дело еще менее благодарное.

Казалось бы "не обновляйте" и живите себе спокойно и мы так и делали для одного из приложений которое просто работало себе спокойно на mongodb2.6

Выбрать одни из самых быстроразвивающихся и меняющихся технологий nodejs + mongo и жаловаться, что продукт на их базе устаревает? Может лучше выбирать более консервативные технологии?

Полностью согласен. Выбор не мой!

Либо это не правда, либо вы не знаете, либо не вы занимались апгрейдом.

Довольно смелое заявление, мягко говоря. Да, как раз с монго 2.6 и начали, потом постепенно до 3.6 заапгрейдили. И я лично апгрейдил. Когда с 2.6 переходил на 3.x и WT, то даунтайм был, конечно. Какие-то несовместимости в новых версиях — это вполне нормально, это всё решалось. По этой же причине пока на 4.x не переехали.


Но вообще-то я спросил лишь про «надёжность не на высоте […] лучше не хранить в Монго критичные данные вообще».

каждый отдельный запрос выполняется относительно медленно (в сравнении с MySQL, например);

Возможно, не используются индексы или они построены неверно.

надёжность не на высоте

Там все хорошо уже давно с надежностью, особенно в 4-х версиях.

К сожалению, я так и не протестировал это самостоятельно. Находил много тестов других организаций занимающихся OLAP хранилищами которые отмечают ее отсталость от PostgreSQL (раз, два) даже в выборках по JSON. Легко верю что и MySQL при грамотной настройке будет работать не хуже MongoDB. Хотя в блоге MongoDB они всегда самые быстрые.

Хотя стоит признать что по удобству работы с JSON объектами MongoDB в разы лучше любой другой СУБД.

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

MongoDB также значительно сокращает цикл разработки приложения по нетехнической причине — устраняется необходимость координации миграции изменений схемы базы данных с DBA.

Если на проекте есть DBA он и до MongoDB доберется. Если нет, то и в SQL проблемы с DBA нет.

Примеры применения написаны в статье хорошо, с оговоркой: никогда не посоветую использовать MongoDB как основное хранилище первичных данных - это в 99% случаев будет выстрел в ногу. Как уже выше писал @yar3333,  "надёжность не на высоте", да и сами разработчики постоянно будут ломать схему, риск поломать данные безвозвратно всегда присутствует. Наиболее распространенное заблуждение - "у нас простая БД что тут можно сломать".

То есть, больше проблема в разработчиках, а не в MongoDB?

НЛО прилетело и опубликовало эту надпись здесь

С Mongo как с гитом - легко выстрелить себе в ногу.

Потому и спросил, так как прозвучало именно в таком ключе. Сам перехожу на MongoDB и хотелось бы знать что не так с этим.

НЛО прилетело и опубликовало эту надпись здесь

Это мне не грозит. Тем более, мне больше интересно было про MongoDB, а не Scala-драйвер для неё.

Сделать кривой драйвер -- дело нехитрое, но это не доказывает глючность MongoDB.

На основе чего был сделан вывод? Если инструмент неудобен и провоцирует делать глупые ошибки - люди будут их делать, потому что они люди. Поэтому я лучше выберу удобный и предсказуемый инструмент для хранения любых данных которые я не хотел бы потерять. А про "надежность" и "предсказуемость" монги я писал выше.

Это не вывод, это вопрос. Просто интересно было знать что не так, так во фразе "надёжность не на высоте" мало подробностей.

Именно. Монга не имеет некоторых механик таких каких как принудительная декларация схемы или контроль целостности Foreign key. Это приводит к повышенным требованиям к гигиене кода. И соответственно у нерадивых разработчиков больше возможностей накосячить

НЛО прилетело и опубликовало эту надпись здесь

Mongo - это не только хранение поля как JSON, а еще и куча фич. Так-то и в mysql есть поддержка JSON.

Так-то PostgreSQL не просто умеет хранить JSON, а ещё и предоставляет поиск и индексацию (GIN) по нему.

Поиск и индексация - это крайне малая часть того, что умеет Mongo и нужно большинству проектов.

НЛО прилетело и опубликовало эту надпись здесь

Про монгу очень много написано, не думаю, что мне тут стоит развернуто про все писать.
Из больших фич:
Aggregation - очень мощная штука, которая позволяет отобрать, отфильтровать и преобразовать данные из БД. Очень удобно для быстроизменяющихся требований ПО, когда структура БД, выбранная на старте сильно меняется уже в процессе развития.

Change Streams - позволяет следить за изменениями данных в real time.

Sharding, Replica set - это все позволяет отмасштабироваться малой кровью.

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

Подскажите, а что будет когда продукт вырастет? Как вы поддерживаете код в согласованном состоянии, когда схема меняется "чуть ли не каждый день"? Не приводит ли это к тому, что проект сразу же становится легаси? Если нет, то за счет чего?

Как вы поддерживаете код в согласованном состоянии, когда схема меняется "чуть ли не каждый день"?

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

Но погодите, если меняются требования - это не просто добавление полей. Это зачастую изменение связей, необходимости уникальности, наличия каких-то значений. Если у вас каждый день добавляется новое nullable поле - это фигня и не требует вообще никаких усилий при написании миграций и в реляицонной БД (а иногда такие поля можно просто сунуть в связанную таблицу key-value-parent_id). А вот когда у вас вместо отношения один-ко-многим стало многие-ко-многим - что делать?

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

А вот когда у вас вместо отношения один-ко-многим стало многие-ко-многим - что делать?

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

база не обрастает пустыми полями

а какая разница? ну кроме того, что не видно какие поля могут встретиться

удаляют поля

это требует миграции, если действительно надо удалить, а не игнорировать в выборках

Ещё кейсы изменения требований:

  • разделить поле на два (с вычислением значения для старых записей)

  • разделить сущность на две с разным жизненным циклом

  • вместо плоского массива строк хранить массив объектов

  • для вложенных объектов ввести единый реестр метаинформации с централизованным редактированием (или наоборот убрать)

Возможно, у меня попадались более изобретательные бизнес аналитики, возможно я сильно промахивался с исходной схемой данных, но я не помню, что бы кейсы добавления nullable-полей требовали каких-то значительных усилий, чтобы их прям очень надо было экономить

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

Реляционная БД с поддержкой SQL - очень мощная штука, которая позволяет отобрать, отфильтровать и преобразовать данные из БД. Очень удобно для быстроизменяющихся требований ПО, когда структура БД, выбранная на старте сильно меняется уже в процессе развития.

Sharding - НЕ позволяет масштабироваться горизонтально если вы активно используете Aggregation! Потому что там однозначно много $unwind и $lookup, а эти операции сведут на нет все горизонтальное масштабирование. А с репликами у вас не будет проблем и с реляционной БД.

Change Streams - Может быть очень полезен. Полностью согласен. Но это узкая область задач.

"Про монгу очень много написано" - По стратегии продвижения монги можно сейлзов учить и многие так и делают. Другое дело что большая часть написанного про монгу имеет мало общего имеет с ценностью для технарей ввиду того что это просто маркетинг.

"Реляционная БД" и "Очень удобно для быстроизменяющихся требований ПО" - ну Вы либо крестик снимите, либо трусы наденьте. Я полагал, что у Вас действительно есть опыт какой-то в суровом энтерпрайзе и миллиардами строк в базе.

Сейчас обидно было...
Но я всегда готов поискать противоречия в том что написал.

  • SQL позволяет отфильтровать и преобразовать данные из БД?

  • SQL позволяет менять схему БД?

Как вы сами написали, чтобы поддерживать код в согласованном состоянии с БД "миграции никто не отменял" что с MongoDB что с SQL. ИМХО, противоречий нет.

Сейчас обидно было...

Простите, честно не хотел Вас обидеть.

Вы упустили слова "Очень удобно" - сознательно или нет - не знаю. Любой разраб, кто сталкивался с большой реляционной БД в проде, знает, как тяжело добавлять новые поля, особенно, когда их и так сотни в таблице или мигрировать схему. В монге это все делается прям таки на порядок проще. Если таких изменений много - то жизнь с монгой будет намного проще, чем с любой реляционной БД. Так, для добавления новых полей миграции для монги писать не нужно в большинстве случаев.

Все так, но это же проблема не SQL. В SQL очень легко добавить новое поле. В Большую БД (и в MongoDB тоже) добавить поле сложно из-за процесса обновления БД между разными окружениями: миграция, code review и пр (если там есть такой процесс). Если же любой разработчик просто лепит поля в документы как ему нравится никого не предупреждая - это быстро и плохо закончится.

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

В Большую БД (и в MongoDB тоже) добавить поле сложно

Для монги это нет так - поле просто не нужно добавлять.

Во многих случаях, реляционная БД при изменении схемы заблочит всю таблицу

Во многих случаях - да. При добавлении колонки - нет (года с 2010+- все популярные SQL решения так могут)

Mysql считаете непопулярным решением? )

При добавлении колонки Mysql начнет делать rebuild всей таблицы. Вы хорошо понимаете, что это для прода значит? Плюс нехреновый такой риск, что если что-то пойдет не так, то для админа будет нескучный денек.

Совсем не обязательно это что-то значит для прода, часто даже downtime допустим. Но да, я не знал, жестковато - может создать приличную нагрузку.

Совсем не обязательно это что-то значит для прода, часто даже downtime допустим.

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

Если бы у меня проходило несколько платежей в секунду через таблицу X. Я бы сделал все чтобы процесс обновления этой таблицы проходил 7кругов ада перед любым обновлением. rebuild таблицы(который кстати пройдет в фоне и без блокировки, если я правильно понял доку) там будет меньшей из проблем. Но да, очевидно, MySQL будет плохим выбором именно для такой таблицы транзакций.

> Тут простой прямых денег стоит.
Тоже не всегда это правда. Нужно понимать еще что вы продаете и как. Небольшой простой такого ресурса просто спровоцирует небольшой всплеск нагрузки после старта. Придут те у кого не получилось до этого. А вот вернутся ли они - это зависит от их мотивации и того что вы продаете, в некоторых случаях у них и выбора не будет. В других, таких как retail, вернется 80-99% (конечно если это не простой в неделю)

Но да, очевидно, MySQL будет плохим выбором именно для такой таблицы транзакций.

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

Добавление они пофиксили, а вот для DROP база все равно rebuild запускает. Честно говоря, последние годы за развитием mysql мало слежу. Все же много у них legacy накопилось, да и альтернатив типа mongodb/elastic много появилось, более удобных в использовании.

Я использовал MongoDB в своей CMS, как основную базу и несказанно рад этому выбору. Основные и главные преимущества это нет схемы и нету этих JOIN'ов.

А Spring Data поверх, решает все проблемы с мерджингом данных и проектированием объектов.

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

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь

Проблемы с количеством документов или с их размерами? Вроде как изначально была речь про размер одного документа.

НЛО прилетело и опубликовало эту надпись здесь

Всегда было интересно как MongoDB относится к таким штукам с большими вложениями, но идея понятна.

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

Вот количество документов относительно много, но проблем с этим не возникает.

Очень просто – хранить там логи, например, или исключения со стектрейсами.

упёрлись в размер документа в 16 мегабайт

Это довольно много, возможно, неверно выбрана архитектура базы.

НЛО прилетело и опубликовало эту надпись здесь

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

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь

Как бы вы не уменьшали размер вложенного документа, если их количество ни чем не ограниченно, то у вас нет 100% гарантии, что однажды вы не упрётесь в лимит 16Мб. 16Мб для большого проекта — это не так и много.

НЛО прилетело и опубликовало эту надпись здесь

Как только я услышал про вложенные документы, подумал - как круто. Открываю документацию: "блабла, такие ограничения, лучше нормализуйте и кладите в две коллекции".

Подумываете об использовании MongoDB?

Не делайте этого.

логирование событий;
управление контентом;
игры;
платежные системы;
аналитика в режиме реального времени;
приложения Интернета вещей;
кеширование;
приложения, обрабатывающие временные ряды.

Не подходит. Возьмите:
Redis/Tarantul для кешей.
ClickHouse для всех логов и временных рядов.
И свой любимый sql для всего остального.
Любая аналитика легко строится поверх этого набора.

И будет вам счастье.

Монга подходит для MVP на коленке. Когда на все, кроме скорости выкатки в прод, все равно. После перехода во что-то более стабильное надо переписывать на нормальные базы. И чем раньше переписать тем лучше.

Аргументов, чем плоха монга, конечно же не будет?

Случаи, когда MongoDB будет хорошим выбором:

Ваши приложения в основном работают с JSON-документами;
Ваши данные непредсказуемы и бывают частые изменения схемы;
Вам требуется высокая доступность и масштабируемость чтения;
Вам нужно масштабировать данные очень большого размера;
Требуется масштабирование из-за огромного количества операций записи.


Надо заменить на:
— ваши данные непрерывно растут, и требуется способ дешевого горизонтального масштабирования

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

У MongoDB всё очень плохо с ETL с другими базами...

У MongoDB есть только один отличительный и важный плюс перед реляционными решениями. И при выборе базы имеет смысл учитывать только его. Это простое шардирование из "коробки".
Это то, ради чего она создавалась. И как писали выше — то из-за чего всё остальное в монге сделано так, как оно сейчас есть.
Если вы не планируете использовать шардирование, то выбор MongoDB в качестве основной базы — очень спорное решение. Для этого надо очень хорошо знать и понимать ради чего же вы её выбираете.
Ну и конечно поддержка шардирования — это не совсем "бесплатная" фича. Часто об этом не говорят, расхваливая монгу. Оно требует правильного проектирования того, как вы храните данные в базе. Не получиться просто так взять и включить шардирование в продакшен базе, которая под это не планировалась.


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


  • Отсутствие схемы — маркетинговая уловка. Схема, и все гарантии связанные с ней, просто переезжает в приложение. Да, это добавляет гибкости — можно навертеть чего угодно. Но усложняет приложения для наиболее типовых ситуаций. Кроме того это увеличивает объёмы базы, т.к. каждый документ, кроме своих данных, хранит так же имена полей. Можно найти рекомендации использовать в MongoDB как можно более короткие имена полей, если есть проблема с местом под базу.
  • Отсутствие JOIN-ов и как решение этой проблемы — денормализация. Это точно не плюс — это просто особенность реализации. Возможности денормализации в монге ограничиваются размером документа (16 Мб по умолчанию). Об этом маркетологи забывают упомянуть. А если надо поддерживать актуальность вложенных документов — это становится головной болью из-за отсутствия в монге транзакций (об этом далее). "Эмуляция" JOIN-ов в приложении — в принципе работающее решение, но не самое дешёвое в плане реализации и требуемых ресурсов. Есть ещё $lookup для агрегаций, но он не работает на шардированных коллекциях. А, как я писал выше, монга без шардирования — это очень странный выбор. Денормализацию можно использовать и в реляционных базах (и типы вроде JSONB этому только помогают).
  • Транзакции — можно считать, что их нет. Они конечно заявлены в версии 4.x, но пока что они работают только в реплик-сетах и без шардирования. Можно конечно и без них прожить, до тех пор пока у вас нет необходимости атомарно вносить изменения более чем в один документ. А как только это понадобится, то придётся навешивать костылей в коде приложения и очень внимательно и аккуратно проектировать структуру коллекций и документов, создавать доп. сущности. Например делать эмуляцию транзакций, что бы после завершения всех изменений можно было обновлением ОДНОГО документа сделать "commit", который сделает изменения "видимыми" для приложения. Плюс делать крон-задчу, которая ищет зависшие "транзакции" и удаляет их. Другой вариант — сделать так, что бы "транзакцию", которая прервалась, можно было продолжить с места обрыва.
    В этом контексте очень странно видеть платёжные системы в списке проектов с Монгой. Надеюсь она там используется для хранения не очень важной информации.

Я уже 9 лет работаю с MongoDB и много раз мы на неё ругались, плевались, писали в приложении больше кода, чем могло бы понадобится если бы были транзакции. Мы заранее понимаем, что любые простые счётчики "документов" в монге по умолчанию врут, и если их значение очень важно — надо писать крон-задачу, которая будет делать агрегацию и обновлять счётчики. Любые задачи, требующие изменения нескольких документов, вызывают "изжогу", т.к. приходится делать выбор: или писать доп. код для обеспечения гарантий, или забить и будь как будет — в случае чего руками в базе поправим.
В данный момент мы не планируем мигрировать с неё на реляционки только из-за шардирования — всё остальные "плюсы" вообще ни как не лочат нас на монгу.

Если думаете о MongoDB, то посмотрите RavenDB как альтернативу.

Очень просто развернуть репликацию и шардирование

Это не правда! Документация мутная, в интернетах куча недоделанных примеров, я не встречал ни одного работающего примера.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий