(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

MongoDb for developers. Неделя 1

Источник: habrahabr
sl4mmer

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

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

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

МонгоДб - не реляционная база данных, предназначенная для хранения JSON-документов. Рассмотрим некий абстрактный экземпляр коллекции монго
{a:3 b:7 fruit:["apple","banana","peach"]} 
Мы видим, что данный документ имеет целочисленные ключи a и b и ключ fruit который является массивом. В реляционных базах подобное поведение невозможно. Стоит отметить, что подобное представление данных гораздо ближе к коду, чем то с которым мы имеем дело работая с реляционными базами данных. 

Коллекции в МонгоДб не привязаны к заранее определенной схеме (schemaless). Например следующие документы, могут быть элементами одной коллекции
{a:1,b2} {a:2,b:4,c:10} 
Вспомните, сколько раз вам приходилось скрипя зубами делать ALTER TABLE, добавляя новое поле, которое то и использовать будут далеко не все элементы? С МонгоДБ подобное осталось в прошлом.

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

Одна из основополагающих идей MongoDb - предоставлять широкий набор возможностей, при сохранении высокой производительности. Конечно чем-то приходится жертвовать. Так например Монго не имеет аналога join: нельзя объединить элементы двух разных коллекций. Вторым важным отличием от реляционных баз данных является отсутствие транзакций. Последнее звучит пугающе, но дело в том, что в монго вам не понадобятся транзакции, в тех ситуациях где они были бы необходимы при использовании реляционной базы.

От слов к делу
Для продолжения нам потребуется установить MongoDb. Вы скорее всего найдете свежую версию в репозитории своего дистрибутива, в случае отсутствия таковой- исходники доступны на официальном сайте. Там же есть бинарники для win и mac. Стоит отметить, что 32х-битная версия имеет существенные ограничения по объему хранимых данных, так что ее можно использовать только для разработки. Сейчас для нас это не принципиально.
Устанавливаем, запускаем и заходим в шелл.

dirtyhack@dirtyhack-ThinkPad-Edge-E125:~$ mongo
MongoDB shell version: 2.0.4
connecting to: test
> 

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

> db.users.save({name:"Woody",age:23});
> db.users.find().pretty()
{
    "_id" : ObjectId("508ea7f33cc5578ed9ecbf46"),
    "name" : "Woody",
    "age" : 23
}
> 

Тут сразу много интересного. Командой db.users.save() мы отправили запрос на сохранение документа в коллекцию users текущей базы данных. Ранее этой коллекции не существовало, она была автоматически создана при запросе.

> show collections
system.indexes
users
>

Мы сохранили в коллекции users простой json-документ, с ключами name и age. О назначении команды find, догадаться несложно - стоит отметить, что в случае когда нас интересует только один документ стоит пользоваться командой findOne(). Команда pretty() не влияет на логику- она просто выводит результат в удобном для чтения виде - без нее, мы бы получили строку, что не удобно при работе со сложными объектами.

Пришло время добавить в коллекцию элемент посложнее, и наглядно продемонстрировать безсхемность монго.

> db.users.save({name:"Bazz",age:23,place_of_birth: {country:"unknown",region:"unknown"},interests:["flying","fighting with evil"]});
> db.users.find({name:"Bazz"}).pretty()
{
    "_id" : ObjectId("508eab333cc5578ed9ecbf47"),
    "name" : "Bazz",
    "age" : 23,
    "place_of_birth" : {
        "country" : "unknown",
        "region" : "unknown"
    },
    "interests" : [
        "flying",
        "fighting with evil"
    ]
}
> 

Второй добавленный нами документ уже более похож на реальные данные. Обратите внимание, что значениями элементов place_of_birth и interests являются вложенные документы- словарь (JSONObject) и массив (JSONArray) соответственно. Иерархическая вложенность - ограничивается здравым смыслом и лимитом в 16 мегабайт на элемент. 

Кстати, мы можем исgользовать встроенный интерпретатор javascript

> var j=db.users.findOne({name:"Woody"})
> j.age=25
25
> db.users.save(j)
> db.users.find({name:"Woody"}).pretty()
{
    "_id" : ObjectId("508ea7f33cc5578ed9ecbf46"),
    "name" : "Woody",
    "age" : 25
}
> 

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

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

Проектирование
Рассмотрим как будет выглядеть структура данных простого веб-приложения в Монго и реляционной базе данных.

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

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

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

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

Пиши код, твою мать.

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

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

Мы создадим простое веб-приложение выводящее на экран имена и возраст пользователей из коллекции users и позволяющее добавлять в коллекцию новые элементы.

Для запуска примера на питоне вам потребуется драйвер pymongo и фреймворк bottle. Для запуска примера на php, вам так же потребуется драйвер, его можно взять из pear(незабудьте добавить mongo.so в список расширений).

Итак примеры
Python
index.py

import bottle
import pymongo
import sys
# Открываем безопасное соединение с локальной базой
# При работе в безопасном режиме, в случае ошибки будет выброшено исключение, но их обработку мы рассмотрим позже
# там все просто
connection=pymongo.Connection("mongodb://localhost",safe=True)
# будем работать с нашей тестовой базой
db=connection.test

@bottle.route('/')
def home_page():
    #Получаем  все элементы коллекции
    users=db.users.find();
    return bottle.template('index',{"users":users})

@bottle.post('/submit')
def submit_page():
    # подготавливаем элемент из данных формы
    user={'name':bottle.request.forms.get("name"),'age':bottle.request.forms.get("age")}
    #Сохраняем
    db.users.insert(user)
    bottle.redirect('/')

bottle.debug()
bottle.run(host="localhost",port=8080)

views/index.tpl

<!DOCTYPE html>
<html>
<head>
    <title>Hello world</title>
</head>
<body>
<p>
   Список пользователей
</p><ul>
    %for user in users:
    <li>Имя:{{user['name']}} Возраст:{{user['age']}}</li>
    %end
</ul>
<form action="/submit" method="POST">
   Добавить нового пользователя<br>
    <input type="text" name="name" size=40 value=""><br>
    <input type="text" name="age" size=40 value=""><br>
    <input type="submit" value="submit">

</form>

</body>
</html>

PHP
Пример на пхп отличается редкой незатейливостью

<?  
    $mongo = new Mongo('localhost');
    $database = $mongo -> test;     
    if ($_POST)
        $database -> users -> insert($_POST);
    
    $users = $database -> users -> find();
?>
<!DOCTYPE html>
<html>
<head>
    <title>Hello world</title>
</head>
<body>
<?var_dump($users)?>
<p>
   Список пользователей
</p><ul>
    <?foreach($users as $user){?>
    <li>Имя:<?=$user['name']?> Возраст:<?=$user['age']?></li>
<?}?>
</ul>
<form action="/" method="POST">
   Добавить нового пользователя<br>
    <input type="text" name="name" size=40 value=""><br>
    <input type="text" name="age" size=40 value=""><br>
    <input type="submit" value="submit">

</form>
</body>
</html>

Важный вопрос к тем, кто заинтересован в примерах на php. В дальнейшем код будет посложнее, можно использовать Yii или ZF, либо самописный микрофреймворк - жду ваших пожеланий.

На этом все, надеюсь не зря старался. Если статья понравится хабражителям - на след неделе, опубликую отчет по второй неделе, на которой будут рассматриваьтся CRUD операции.

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 02.11.2012 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
SAP Crystal Reports XI R2 Dev 2006 INTL WIN NUL License (Version 11)
WinRAR 5.x Standard Licence - для частных лиц 1 лицензия
Panda Internet Security - ESD версия - на 1 устройство - (лицензия на 1 год)
ESET NOD32 Антивирус на 1 год для 3ПК или продление на 20 месяцев
ABBYY Lingvo x6 Европейская Домашняя версия, электронный ключ
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Безопасность компьютерных сетей и защита информации
Новости ITShop.ru - ПО, книги, документация, курсы обучения
OS Linux для начинающих. Новости + статьи + обзоры + ссылки
Реестр Windows. Секреты работы на компьютере
Один день системного администратора
Компьютерная библиотека: книги, статьи, полезные ссылки
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100