Открытый вебинар «Основы MongoDB»

    Друзья, очередной запуск курса «Базы данных» состоится уже завтра, поэтому мы провели традиционный открытый урок, запись которого вы можете посмотреть здесь. В этот раз поговорили о популярной БД MongoDB: изучили некоторые тонкости, рассмотрели основы работы, возможности и архитектуру. А также коснулись некоторых User Cases.



    Вебинар провёл Иван Ремень, руководитель направления серверной разработки в «Ситимобил».



    Особенности MongoDB


    MongoDB — документоориентированная СУБД с открытым исходным кодом, не требующая описания схемы таблиц. Она классифицируется как NoSQL и использует BSON (бинарный JSON). Масштабируется из коробки, написана на языке C++ и поддерживает синтаксис JavaScript. Поддержка SQL отсутствует.

    У MongoDB есть драйверы для многих популярных языков программирования (Си, C++, C#, Go, Java, JavaScript, Perl, PHP, Python, Ruby и др.). Также есть неофициальные и поддерживаемые сообществом драйверы для прочих языков программирования.

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

    Итак, чтобы развернуть MongoDB в Docker, пишем:

    docker run -it --rm -p 127.0.0.1:27017:27017 
    --name mongo-exp-project mongo
    docker exec -it mongo-exp-project mongo

    Таким образом, происходит запуск клиента MongoDB:



    А теперь напишем традиционный Hello World:

    print (“Hello world!”)



    После этого — запустим цикл:



    Как вы заметили, перед нами обычный JS, а MongoDB — это полноценный интерпретатор JavaScript.

    Когда применять MongoDB?


    Есть байка о том, что средний стартапер в кремниевой долине — это человек, который неделю назад открыл книжку «HTML для чайников». Какой он выберет стек? Согласитесь, что ему очень удобно, когда у него в браузере по очевидным причинам находится JavaScript, на сервере крутится Node.js, а в базе данных тоже JavaScript. Это момент № 1.

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

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

    Что касается терминологии в MongoDB, то:

    • базы — это базы (схемы, совокупность таблиц);
    • в MongoDB есть такое понятие, как коллекция — это аналог таблицы и набор документов, которые по логике вещей должны быть связаны;
    • документы — это аналог строки.

    Создание базы данных и простые запросы


    Чтобы создать базу данных, нужно просто начать её использовать:

    use learn



    Теперь сделаем небольшую вставочку документа. Пусть это будет, к примеру, единорог с именем Аврора:

    db.unicorns.insert({name: 'Aurora', gender: 'f', weight: 450})

    db — глобальный объект для доступа к БД, то есть, по сути, сама «монга». Для шардинга используется sh, для репликации — rs.

    Какие команды есть у объекта db:



    Итак, вернёмся к нашей команде, в результате применения которой консоль сообщит, что вставлена одна строка:



    Слово unicorns в команде db.unicorns.insert({name: 'Aurora', gender: 'f', weight: 450}) обозначает коллекцию. Здесь обратите внимание, что мы коллекцию не описывали и не создавали, а просто написали ‘unicorns’, сделали insert, и у нас появилась коллекция.

    А вот так мы сможем получить все наши коллекции:

    db.getCollectionNames()

    Ну и так далее. Можем вставить ещё одну коллекцию:



    А теперь запросим полную коллекцию (напоминаем, что в нашем случае в базе данных уже находится информация о двух единорогах с одинаковым именем):

    db.unicorns.find()

    Обратите внимание, вот и наш JSON (есть имя, пол, вес, некий уникальный идентификатор объекта):



    Теперь давайте вставим ещё парочку единорогов с одинаковыми именами:

    db.unicorns.insert({name: 'Leto', gender: 'm', 
    home: 'Arrakeen', worm: false}) 
    db.unicorns.insert({name: 'Leto', gender: 'm', 
    home: 'Arrakeen', worm: false})

    И посмотрим, что получилось:



    Как видите, у нас появились дополнительные поля: home и worm, которых нет у Авроры.

    Добавим ещё несколько единорогов:

    db.unicorns.insertMany([{name: 'Horny', dob: new Date(1992,2,13,7,47), loves: ['carrot','papaya'], weight: 600, gender: 'm', vampires: 63}, 
    {name: 'Aurora', dob: new Date(1991, 0, 24, 13, 0), loves: ['carrot', 'grape'], weight: 450, gender: 'f', vampires: 43}, 
    {name: 'Unicrom', dob: new Date(1973, 1, 9, 22, 10), loves: ['energon', 'redbull'], weight: 984, gender: 'm', vampires: 182}, 
    {name: 'Roooooodles', dob: new Date(1979, 7, 18, 18, 44), loves: ['apple'], weight: 575, gender: 'm', vampires: 99}])

    Итак, мы вставили с помощью JavaScript ещё четыре объекта:



    Как вы думаете, в каких БД удобнее хранить паспортные данные: в реляционных БД или в монге?

    Ответ очевиден — в монге, и вышеописанный пример хорошо это показывает. Не секрет, что КЛАДР — это боль в РФ. А монга очень хорошо ложится на адреса, ведь можно задать всё как массив, и будет гораздо проще жить. И это хороший User Case для MongoDB.

    Добавим ещё единорогов:

    db.unicorns.insert({name: 'Solnara', dob: new Date(1985, 6, 4, 2, 1), loves:['apple', 'carrot', 'chocolate'], weight:550, gender:'f', vampires:80}); 
    db.unicorns.insert({name:'Ayna', dob: new Date(1998, 2, 7, 8, 30), loves: ['strawberry', 'lemon'], weight: 733, gender: 'f', vampires: 40}); 
    db.unicorns.insert({name:'Kenny', dob: new Date(1997, 6, 1, 10, 42), loves: ['grape', 'lemon'], weight: 690, gender: 'm', vampires: 39}); 
    db.unicorns.insert({name: 'Raleigh', dob: new Date(2005, 4, 3, 0, 57), loves: ['apple', 'sugar'], weight: 421, gender: 'm', vampires: 2}); 
    db.unicorns.insert({name: 'Leia', dob: new Date(2001, 9, 8, 14, 53), loves: ['apple', 'watermelon'], weight: 601, gender: 'f', vampires: 33}); 
    db.unicorns.insert({name: 'Pilot', dob: new Date(1997, 2, 1, 5, 3), loves: ['apple', 'watermelon'], weight: 650, gender: 'm', vampires: 54}); 
    db.unicorns.insert({name: 'Nimue', dob: new Date(1999, 11, 20, 16, 15), loves: ['grape', 'carrot'], weight: 540, gender: 'f'}); 
    db.unicorns.insert({name: 'Dunx', dob: new Date(1976, 6, 18, 18, 18), loves: ['grape', 'watermelon'], weight: 704, gender: 'm', vampires: 165});



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

    Кстати, для более красивого вывода результатов, можно в конце команды поиска вызвать метод .pretty():



    Если нужно получить информацию о последней ошибке, используем следующую команду:

    db.getLastError()

    Это можно делать после каждой вставки, либо настроить Write Concern. Лучше почитать об этом в официальной документации, которая, кстати, в монге весьма содержательная. Кстати, на хабре тоже есть неплохая статья по этому поводу.

    Переходим к более сложным запросам


    Запрос по точному значению поля:

    db.unicorns.find({gender: 'm'})

    Написав такой запрос, мы получим в выводе на консоли список всех единорогов-мужчин.

    Также можно выполнить запрос сразу по нескольким полям: по полу и по весу:



    Выше обратите внимание на специальный селектор $gt, который позволяет вывести всех единорогов мужского пола весом более 700.

    Можно проверить, существует ли поле вообще:

    db.unicorns.find({vampires: {$exists: false}})

    Или так:

    db.unicorns.find({'parents.father': {$exists: true}})

    Следующая команда выведет единорогов, имена которых начинаются с букв А или а:

    db.unicorns.find({name: {$regex: "^[Aa]"}})

    Теперь рассмотрим поиск по массиву. Вопрос № 1: что выведет эта команда:

    db.unicorns.find({loves:'apple'})

    Правильно: всех, кто любит яблоки.

    Следующая команда вернёт лишь те данные о единороге, в которых содержатся только яблоки и арбузы:

    db.unicorns.find({loves:[ "apple", "watermelon" ]})

    И ещё одна команда:

    db.unicorns.find({loves:[ "watermelon", "apple" ]})

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

    А вот так выглядит поиск по массиву с использованием оператора «ИЛИ»:



    Следующий пример продемонстрирует нам поиск с использованием оператора $all. И здесь уже последовательность непринципиальна:



    Также мы можем искать и по размеру массива:



    А что делать, если мы хотим найти массив, у которого размер больше единицы? Для этого существует оператор $where, с помощью которого можно писать более сложные вещи:

    db.unicorns.find({$where: function() { return this.loves && (this.loves.length > 1) } })

    Кстати, если хотите попрактиковаться, вот вам файлик с командами.

    Особенности курсора


    Немного отвлечёмся и скажем пару слов про особенности монги:

    • find() и другие операции не возвращают данные — они возвращают так называемый «курсор»;
    • то, что мы видим, как данные печатаются, есть работа интерпретатора.

    Набрав db.unicorns.find без скобок, мы получим подсказку:



    Продолжаем выполнять запросы


    Есть ещё оператор $in:

    db.unicorns.find({weight: {$in: [650, 704]}})



    Теперь поговорим про update. Например, давайте изменим вес единорога Roooooodles:

    db.unicorns.update({name: "Roooooodles"}, {weight: 2222})

    В результате наших действий документ полностью обновится, а в нём останется только одно указанное поле:



    То есть единственное, что останется у нашего объекта — это вес 2222 и, разумеется, id.

    Исправить ситуацию можно с помощью $set:

    db.unicorns.update({_id: ObjectId("5da6ea4d9703b8be0089e6db")}, {$set: { "name" : "Roooooodles", "dob" : ISODate("1979-08-18T18:44:00Z"), "loves" : [ "apple" ], "gender" : "m", "vampires" : 99}})




    Также есть возможность инкрементировать значения:



    А ещё есть upsert — комбинация update и insert:



    А вот как осуществляется выборка полей:





    Остаётся добавить пару слов про skip и limit:



    Коллеги, на этом всё, если хотите узнать подробности, смотрите видео целиком. И не забывайте оставлять свои комментарии!
    • +11
    • 2,8k
    • 6
    OTUS. Онлайн-образование
    688,19
    Цифровые навыки от ведущих экспертов
    Поделиться публикацией

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

      0
      Ответ очевиден — в монге, и вышеописанный пример хорошо это показывает

      А если ответ не очевиден, а аргументация непонятна, обновление монги до более новой версии не поможет?

        0
        Мы в DataGrip делаем поддержку Монги, которая выйдет в декабре. Будем рады, если вы попробуете и расскажете и своих впечатлениях, что можно улучшить и так далее.
          0
          А как плагин к идее можно использовать?
            0
            Конечно
              0
              Отлично! а где можно тогда о впечатлениях рассказать? :)
                0
                Напишите на datagrip@jetbrains.com. Спасибо!

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

        Самое читаемое