Для чего нужен mongodb

В чем особенности MongoDB и когда эта база данных вам подходит: руководство для новичков

Подготовили небольшой гайд по СУБД MongoDB: вы узнаете, в чем ее особенности, плюсы и недостатки, для каких проектов она подходит, а когда лучше выбрать реляционную базу данных.

Что такое база данных MongoDB и в чем ее особенности

MongoDB — документоориентированная система управления базами данных с открытым исходным кодом. Для хранения данных используется JSON-подобный формат. Эта СУБД отличается высокой доступностью, масштабируемостью и безопасностью.

Главные особенности MongoDB:

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

Пример документа в MongoDB

На схеме показано, как выглядит документ в MongoDB:

Для чего нужен mongodb. Смотреть фото Для чего нужен mongodb. Смотреть картинку Для чего нужен mongodb. Картинка про Для чего нужен mongodb. Фото Для чего нужен mongodb

MongoDB добавляет поле _id с уникальным значением для идентификации документа в коллекции. Это поле обязательно для заполнения в каждом документе. Оно похоже на первичный ключ документа. Если вы создаете новый документ без поля _id, то MongoDB автоматически создаст его и добавит 24-значный уникальный идентификатор к каждому документу в коллекции.

Структура хранилища MongoDB

СУБД MongoDB полагается на концепции базы данных, коллекций и документов. Рассмотрим основные термины, а для лучшего понимания сравним их с терминами из языка структурированных запросов (SQL):

Зачем использовать MongoDB: преимущества этой СУБД

Ниже приведены несколько причин, по которым стоит использовать MongoDB:

Недостатки MongoDB

Вот основные минусы MongoDB:

Когда стоит и не стоит использовать MongoDB

MongoDB часто выбирают, когда нужна масштабируемая база данных, в настоящее время ее используют в качестве хранилища внутренних данных многие организации, такие как IBM, Twitter, Zendesk, Forbes, Facebook, Google и другие.

Примеры, когда MongoDB подходит для проекта:

Источник

Почему мы выбрали MongoDB

Эта статья появилась на свет после прочтения материала «Почему вы никогда не должны использовать MongoDB». Ниже — история о том, как мы постепенно отказались от MySQL и пришли к использованию MongoDB в качестве основного хранилища данных.

Для чего нужен mongodb. Смотреть фото Для чего нужен mongodb. Смотреть картинку Для чего нужен mongodb. Картинка про Для чего нужен mongodb. Фото Для чего нужен mongodb

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

Первым делом были сформулированы:

Требования

В основном это требования именно к базе данных.
Из существенных можно выделить:

Требование 1. Мультиязычные поля

Каждая запись может иметь одно или несколько мультиязычных полей, содержащих как относительно короткие названия, так и длинные описания. Думали над разными вариантами:

Вариант 1. Две таблицы на всю базу

Соответственно, если у игры (таблица game) есть мультиязычное имя name, альтернативное имя alt_name и описание desc, то получилось бы, помимо самой игры, еще три записи на язык.

Пример записей в таблице name:

Пример записи в таблице description:

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

Вариант 2. Для каждой основной таблицы — своя мультиязычная

Для той же таблицы игр получится примерно следующее:

Вариант 3. Мультиязычные поля сохранять в виде json-массива в отдельном поле основной таблицы

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

В итоге мы остановились на варианте 2. Против первого варианта было то, что у мультиязычных полей могут быть свои дополнительные поля. Например, в играх нужна возможность пометить одно из названий как главное, у других объектов может быть свой набор дополнительных полей, по которым, вполне возможно, еще и нужно будет фильтровать/сортировать. Не хотелось в итоге при выборе первого варианта через пару лет прийти вот к такому:

И потом в коде вспоминать — что такое field3 у таблицы компаний. Кроме того, как-то некомфортно, создавая очередную таблицу с пятью записями, сваливать переводы в таблицу с миллионом записей. Впрочем, последнее во всей красе проявилось тут:

Требование 2. Связи

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

Вариант 1. Одна таблица для всех связей базы

Записи #2 и #3 реализуют двунаправленную связь, запись #1 — однонаправленную от игры к жанру.

Вариант 2. Для каждого типа связи своя таблица

К примеру, связи между похожими играми получились бы такими:

и так далее для каждого типа связи.

Вариант 3. Храним связи в самом объекте в текстовом виде

Тогда можно будет искать как-то так:

Вариант 4. Аналог варианта 3, но храним json

Варианты 5 и 6. Для каждого типа связи свое поле.

Вариация вариантов 3 и 4, но связи раскидываются по разным полям.

В итоге решили хранить все в одной таблице (удобно же), плюс, в отдельных случаях можно было бы дублировать информацию о связях в полях самого объекта (варианты с третьего по шестой). Плодить для каждого типа связи свою таблицу не хотелось, и помочь мог третий вариант. Конечно, делать links like ‘%#game:$game2_id#%’ — это ужасно, но я бы пережил. Отказались же от этого варианта потому, что удаление записей превращалось в нетривиальную задачу. Четвертый и шестой варианты сами по себе вообще бесполезны.

Требование 3. Объекты с разным набором полей в одной таблице

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

Способы решения, как хранить метаданные, те же самые, что и выше. Создается одна таблица, в которой будут общие для всех типов записей поля. А далее вариантов немного. Можно хранить все метаданные прямо в тексте поста (или в отдельном текстовом поле) специальными тегами, как это сделано в Википедии, а при сохранении раскидывать по связанным вспомогательным таблицам. Можно сразу создать вспомогательные таблицы для каждого из типов поста и сохранять метаданные туда (этот вариант мы и выбрали, тем более что для разных типов постов все равно создавались разные формы редактирования в админке). Можно хранить метаданные в виде json или любом другом сериализованном виде (проблемы тоже все те же — сложность изменения таких сериализованных данных средствами SQL, плюс сортировки/фильтрации).

Требование 4. Сложные объекты

Игра может быть выпущена на разных платформах и для каждой платформы может иметь разные издания. У релиза на платформе и у издания есть набор полей, совпадающий с самой игрой. Пример такого поля — «Название», так как, например, название издания для конкретной платформы может отличаться от каноничного названия игры. Также у платформы и издания есть набор полей, которых нет в самой игре, например, для платформы это будет собственно сама платформа, у издания — дата его релиза. Как все это хранить? В виде трех раздельных таблиц? По аналогии с тем, как решается хранение объектов с разным набором полей в требовании 3? Или хранить саму игру в виде одной записи, а все платформы и издания — в виде json в отдельном поле этой записи? И как такую радость редактировать? Делать три разные формы? У той же Pac-Man 27 платформ и более 30 изданий, редактирование такого монстра может превратиться в пытку. А как это показывать? Например, чтобы показать издание, придется для него загрузить платформу и саму игру, потому что, например, у издания может не быть своего названия. Тогда нужно смотреть общее название игры на платформе, а если там его нет, то смотреть название самой игры. При этом заранее прописать всем изданиям совпадающее название — тоже не здорово.

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

MySQL

Определившись с требованиями и предварительными вариантами их решения, мы начали разрабатывать админку. И тут (впрочем, как и всегда) начались проблемы. Например, у компании может быть название и описание. Создаем одну таблицу company_i18n с полями name и description. Пока все идет хорошо. В форме редактирования

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

Записи в company_i18n после сохранения:

Потом оказалось, что описаний на одном языке может быть несколько, а название должно быть строго одно для языка, и мы приходим к чему-то типа:

Уже не очень хорошо выглядит, особенно если нужно удалить “Описание 2” с помощью SQL — нужно смотреть, есть ли название в поле name, и если оно есть, обновлять запись, а если нет, то удалять. Потом у названия компании появляется флаг “основное”, появляется поле для корпоративных названий, которых может быть несколько на одном языке (для разных периодов времени свое), и приходит понимание, что, похоже, придется хранить имена и описания в разных таблицах.

У связей между объектами почти сразу появилась сила связи. Это не было проблемой, проблемы начались, когда для разных типов связей появился свой набор дополнительных полей. Например, жанры могут быть связаны с другими жанрами и являться их поджанрами, и связь должна быть двунаправленной: в тегах одни теги являются персонажами из другого тега-вселенной, а у игр одна и та же компания может быть как разработчиком, так и издателем. И хотя проблему можно решить, добавив новые поля в таблицу link, но правильнее будет для отдельных типов связей создавать отдельные вспомогательные таблицы.

Я, конечно, понимаю, что жизнь — это боль, и разработчик (в частности) должен не забывать страдать, поэтому разработка медленно, но верно продолжалась, а вспомогательные таблицы появлялись с завидной регулярностью. Тем не менее, хотелось как-то автоматизировать процессы создания таких вот вспомогательных таблиц и сборки полного объекта из них. С такими мыслями в начале 2010 года я наткнулся на статью “Как FriendFeed использует MySQL для хранения данных без схемы”.

MySQL и данные без схемы

Идея сделать NoSQL поверх MySQL выглядит не так уж и безумно даже сейчас. На тот момент MySQL развивалась уже годами и являлась надежным решением для production, а специализированные NoSQL решения только начали появляться, и не хотелось, сделав выбор в пользу чего-то одного, через пару лет оказаться один на один с не поддерживаемым продуктом. Я думаю, те, кто, как и я в свое время, сделал ставку на prototype.js, меня поймут.

В то время MongoDB мы даже не рассматривали по разным причинам, в частности, ее пока не рекомендовали для production (первый production ready релиз был в конце первого квартала 2010-го). Я до сих пор сторонник такого подхода: использовать для проектов относительно устоявшиеся решения и по минимуму привлекать самописные аналоги. Но тогда устоявшихся решений еще не было (или казалось, что их нет), и для одного из своих сторонних проектов я написал что-то похожее на то, что было у FriendFeed. Поймите меня правильно: я этим не горжусь — идея сделать что-то свое может быть заманчивой ровно до тех пор, пока не придется это что-то поддерживать, фиксить «баги», оптимизировать, развивать функциональность, адаптировать к новым версиям языка/библиотек/используемых сервисов. Единственное, о чем я жалею — нужно было тогда скачать и пощупать «монгу», это дело получаса, максимум часа, а пользы — на годы. Собственно, это касается всех новых технологий: появляются они не просто так, и знание современных тенденций позволяет элементарно расширять кругозор.

Итак, была написана библиотека для работы с данными без схемы и хранением всего этого в MySQL.

Объекты хранились в сериализованном виде в blob поле таблицы entity. Было введено дополнительное поле category (аналог таблиц в MySQL и коллекций в MongoDB), чтобы можно было разделять объекты, например игры, компании и т.п. (от варианта, когда, например, все сообщения хранятся в объекте темы, мы почти сразу отказались — для сообщений своя категория, для темы своя), плюс два поля — время создания и обновления объекта. Так как писалось все на Perl, то использовалась библиотека Storable для сериализации структур данных (обычно комбинация хэшей и массивов) из внутреннего представления в бинарный вид и обратно. В первую очередь это было сделано из-за скорости, в json данные конвертировались на порядок медленнее. Во вторую — из-за более компактного представления по сравнению с json.

В качестве id испольовался uuid, 16 байт которого кодировались с помощью base 64 в текстовую строку длиной 22 байта.

На любые изменения объекта можно было вешать “триггеры” — функции, которые изменяли как сам объект, так и другие объекты, связанные с текущим. Например, при написании комментария триггер может менять общее количество комментариев в объекте темы.

Так как по таблице entity никаких запросов (кроме как по первичному ключу и категории) делать было нельзя, были введены индексы — обычные MySQL таблицы, которые создавались на основании полей сохраняемого объекта.

В конфиге прописывалось:

Тогда при сохранении объекта:

В index_platform автоматом создавалась запись:

По этим индексам уже можно было делать выборки:

Альтернативный вариант того же самого запроса:

Существовало только два типа взаимодействия с БД: это изменение самих объектов в таблице entity (включая удаление) и запросы к индексам как в примере выше. JOIN только программный.

При удалении объекта он только помечался как удаленный, физически не удаляясь из таблицы entity.

Примерно к середине 2010-го попробовали перейти на этот способ хранения данных.

Объекты теперь можно было сохранять вот в таком виде:

По полю name и link автоматически создавались записи в индексных таблицах index_name и index_link. Объекты могли быть любой сложности и вложенности, с разным набором полей для объекта из одной category. Приходилось по-прежнему создавать индексные таблицы, но стало гораздо проще. Если какого-то поля не хватало, достаточно было поменять код, а если по этому полю нужно было делать выборки — создавалась дополнительная индексная таблица или менялась существующая. Если какой-то индекс не устраивал, его можно было просто удалить и построить новый. В перспективе я хотел сделать создание таких индексных таблиц автоматически по описанию их структуры в коде.

В процессе эксплуатации вылезали разные «баги» самого хранилица, из наиболее неприятных — зависимость алгоритма сериализации объектов в библиотеке Storable от операционной системы. Это решили переходом на хранение объектов в виде json со сжатием с помощью gzip. Кстати, именно во время исправления этого «бага» я четко осознал, что не важно, как хранятся сами объекты. Это может быть отдельная таблица в базе данных, а можно сохранять тупо в виде json файлов, назвав их по первичному ключу и раскидывая по подпапкам (впрочем, это лишает само приложение масштабируемости, будут возникать проблемы из-за race condition и т.п., хотя, с другой стороны, можно было бы попробовать Hadoop, но, откровенно говоря, это было бы уже лишним). Главное — иметь возможность для объектов создавать индексы, как это сделано, например, в поисковой системе Sphinx. Почему бы не воспринимать MySQL примерно так же, как и Sphinx? Почему бы хранение данных не представить в виде key-value хранилища, а для поиска, сортировки и выведения пользователю различных списков создавать подходящие для этого индексы в подходящих для этого сервисах? Конечно, если создается биллинг, то такой подход, мягко говоря, не очень оправдан, но web-приложения в основной своей массе менее требовательны к наличию того же ACID, а мучаться приходится почти так же, как и с биллингом.

Тем не менее, постепенно минусы при использовании самописного хранилища начали перевешивать, а также по-прежнему для каждого объекта нужно было рисовать свою форму в админке, одним словом — не было той универсальности, которой хотелось. Плюс ко всему на AG в 2012 году произошел ряд скорее политических событий, таких как смена владельца сайта, руководства и менеджмента, и было принято решение писать вторую версию на языке Python, поскольку программисты в новой компании писали именно на этом языке. Вариантов было два — либо текущее хранилище оформлять как standalone сервис, либо использовать какое-либо существующее key-value хранилище.

MongoDB

Как бы вы себя чувствовали, если бы однажды оказалось, что кто-то создал аналог вашей библиотеки (ну или наоборот — вы создали некий аналог уже существующей библиотеки, не зная об этом), и этот аналог при сохранении существенных плюсов вашего решения еще и не обладал его минусами? Лично я порадовался. Великолепная консоль с полноценной поддержкой Javascript, атомарные операции, шардинг, автоматическое создание индексов по выбранным полям, библиотеки для основных языков программирования… На тот момент уже существовали фреймворки на Python, которые поддерживали MongoDB или были написаны специально под нее. И все это не нужно было ни поддерживать, ни развивать. Да вдобавок еще и api было похоже на api хранилища.

В результате, начав с нуля (уже в качестве Riot Pixels) разработку на Python в 2013 году, мы, правильно выбрав инструменты (одним из которых была MongoDB), за квартал сделали больше, чем раньше делали за два года. Еще одним из, как мне кажется, правильных решений был выбор админки, которая позволяла редактировать объекты любой вложенности, — из-за этого на ее разработку почти не тратилось времени.

Закончить хотелось бы вот чем. Наверное, неправильно противопоставлять MongoDB и MySQL, ибо для разных задач они подходят по-разному, и так уж получилось, что в этом проекте нам больше подошла MongoDB. Если вдруг такое случится и станет не хватать скорости или функциональности MongoDB — ничто не помешает использовать MySQL в качестве кэширующей прослойки / индекса для данных — один раз настроить и забыть.

Источник

Введение в MongoDB

Что такое MongoDB

MongoDB реализует новый подход к построению баз данных, где нет таблиц, схем, запросов SQL, внешних ключей и многих других вещей, которые присущи объектно-реляционным базам данных.

Со времен динозавров было обычным делом хранить все данные в реляционных базах данных (MS SQL, MySQL, Oracle, PostgresSQL). При этом было не столь важно, а подходят ли реляционные базы данных для хранения данного типа данных или нет.

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

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

Формат данных в MongoDB

Одним из популярных стандартов обмена данными и их хранения является JSON (JavaScript Object Notation). JSON эффективно описывает сложные по структуре данные. Способ хранения данных в MongoDB в этом плане похож на JSON, хотя формально JSON не используется. Для хранения в MongoDB применяется формат, который называется BSON (БиСон) или сокращение от binary JSON.

BSON позволяет работать с данными быстрее: быстрее выполняется поиск и обработка. Хотя надо отметить, что BSON в отличие от хранения данных в формате JSON имеет небольшой недостаток: в целом данные в JSON-формате занимают меньше места, чем в формате BSON, с другой стороны, данный недостаток с лихвой окупается скоростью.

Кроссплатформенность

MongoDB написана на C++, поэтому ее легко портировать на самые разные платформы. MongoDB может быть развернута на платформах Windows, Linux, MacOS, Solaris. Можно также загрузить исходный код и самому скомпилировать MongoDB, но рекомендуется использовать библиотеки с офсайта.

Документы вместо строк

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

Ключ представляет простую метку, с которым ассоциировано определенный кусок данных.

Коллекции

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

Репликация

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

Простота в использовании

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

GridFS

Одной из проблем при работе с любыми системами баз данных является сохранение данных большого размера. Можно сохранять данные в файлах, используя различные языки программирования. Некоторые СУБД предлагают специальные типы данных для хранения бинарных данных в БД (например, BLOB в MySQL).

Источник

Когда использовать MongoDB

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

Бесстуктурность

Запись

Устойчивость

Устойчивость данных упоминается здесь потому, что много сил было затрачено для того, чтобы добиться её в пределах одного сервера. Вы рано или поздно найдёте в Google упоминания о ненадёжности Mongo как хранилища. Однако эта информация уже устарела.

Полнотекстовый поиск

В будущих релизах, надеюсь, полнотекстовый поиск придёт в MongoDB. С поддержкой для массивов базовый полнотекстовый поиск будет довольно просто применять. Для мощных приложений скорее всего понадобится использовать нечто вроде Lucene или Solr. Конечно также это справедливо и для реляционных баз данных.

Транзакции

Поддержка вложенных документов и бесструктурная архитектура MongoDB делают двухфазные коммиты не такими уж страшными, но всё равно это сложный процесс, особенно для тех, кто впервые с этим сталкивается.

Обработка данных

Для большинства задач обработки данных MongoDB использует MapReduce. Есть, конечно, некоторые базовые агрегирующие функции, но для чего-либо серьёзного вам понадобится MapReduce. В следующей главе мы рассмотрим MapReduce более детально. Сейчас можете считать его очень мощным и альтернативным вариантом group by (что, впрочем, будет преуменьшением его возможностей). Одно из преимуществ MapReduce в том, что для работы с большими объёмами данных он может выполняться параллельно. Однако реализация MongoDB основана на JavaScript, который сам по себе однопоточен. Что из этого следует? Для обработки больших данных вам, скорее всего, придётся полагаться на что-то другое, например, на Hadoop. К счастью, эти две системы настолько дополняют друг друга, что существует MongoDB адаптер для Hadoop.

Конечно, распараллеливание обработки данных не является однозначным предметом превосходства реляционных баз данных. В будущих релизах MongoDB планируется улучшить обработку огромных объёмов данных.

Геопространственные данные

Особенно мощной функцией MongoDB является её поддержка геопространственных индексов. Это позволяет сохранять x- и y- координаты у документов и затем находить документы вблизи ($near) определённых координат, или внутри ($within) прямоугольника либо окружности. Это легче понять визуально, поэтому я советую посмотреть пятиминутный практикум по геопространственным функциям MongoDB, если хотите углубить свои знания.

Инструментарий и зрелость

В этой главе

Идея этой главы в том, что MongoDB в большинстве случаев способна стать заменой реляционной базе данных. Она намного проще и понятнее; быстрее работает и имеет меньше ограничений для разработчиков приложений. Отсутствие транзакций может вызывать серьёзную и правомочную озабоченность. Однако, когда спрашивают какое место занимает MongoDB в экосистеме современных механизмов хранения?, ответ прост: строго посередине.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *