Это вторая часть из цикла статей про python и NoSQL (первая - про redis).
Теория
MongoDB один из представителей класса NoSQL (Not Only SQL), относится к документно-ориентированным базам данных с не фиксированной схемой данных. Проект является open-source и написан на C++. Для обмена данными с клиентом используется JSON, а данные хранятся в двоичном формате BSON.
Основной структурной единицей в MongoDB есть документ - упорядоченный набор ключей с связанными значениями. Документы в MongoDB представлены абстрактным типом данных, а конкретная реализация зависит от используемого драйвера. Сами документы хранятся в BJON, бинарном формате, который может хранить документы, как последовательность байтов. Пример представление документа на JavaScript*, в виде объекта:
{"firstword" : "Hello world!"}
MongoDB поддерживает шесть типов данных (null, boolean, numeric, string, array и object.) и является type-sensitive и case-sensitive.
В иерархии структур данных, в MongoDB, над документами находятся - коллекции, которые представляют собой группы документов. Если провести аналогию с таблицами в реляционных БД, то документы будут рядами, а коллекции - таблицами.
Существуют некоторые ограничения в MongoDB: за раз можно вставить 16MB данных, размер документов не может превышать 4MB, размер данных для 32-битной версии mongod ограничен до ~2.5 GB.
В качестве storage engine в MongoDB используется memory-mapped file (отображение файла на память) со всеми вытекающими отсюда плюсами и минусами. MongoDB не подвержен атакам типа инъекции (injection attacks), т.к. не выполняет никакого кода при инсертах.
Еще про теоретическую часть о MongoDB:
Сравнение с другими типами БД:
Нагрузочное тестирование есть тут. Список компаний, использующих MongoDB в продакшене.
Пощупать MongoDB можно на try.mongodb.org, а тут есть cheat sheet по командам.
Установка
Установим MongoDB на Ubuntu. Описание установки на Centos/Fedora/RedHat есть тут.
Берем последнюю стабильную версию отсюда.
wget http://fastdl.mongodb.org/linux/mongodb-linux-i686-1.6.3.tgz
Распаковываем:
tar -xvf mongodb-linux-i686-1.6.3.tgz -C /opt/
Создадим папку для данных и файл для логов
sudo mkdir /var/lib/mongodb/ sudo chown `id -u` /var/lib/mongodb/ sudo touch /var/log/mongodb.log sudo chown `id -u` /var/log/mongodb.log
Создадим конфигурационный файл для mongod
sudo vim /etc/mongod.conf
и запишем в него
port = 5586 fork = true # daemonize it! logpath = /var/log/mongodb.log dbpath = /var/lib/mongodb/
теперь создадим скрипт для запуска mongod с выше определенными параметрами
sudo vim /usr/bin/mongod
и запишем в него
/opt/mongodb-linux-i686-1.6.3/bin/mongod --config /etc/mongod.conf
настроем права
sudo chown `id -u` /usr/bin/mongod sudo chmod ug+x /usr/bin/mongod sudo chown `id -u` /etc/mongod.conf
Все, можно запускать демон с помощью mongod.
Запустим shell и попробую что-то сделать:
/opt/mongodb-linux-i686-1.6.3/bin/mongo --port 5586
> db.test.save({message:'mongodb'})
> db.test.save({message:'nosql'})
> db.test.find()
{ "_id" : ObjectId("4cdeadbd637b7e915544335a"), "message" : "mongodb" }
{ "_id" : ObjectId("4cdeadc3637b7e915544335b"), "message" : "nosql" }
Использование с Python
Для работы Python с MongoDB существует базовый модуль pymongo (документация). На базе pymongo построены два известных ODM: mongokit и mongoengine. Хорошие сравнение mongokit vs mongoengine есть тут. Еще один ODM - mongoalchemy.
Установим последнюю версию pymongo
pip install pymongo
Для примера возьмем две сущности Киноман и Фильм. Каждый киноман имеет собственную оценку по фильму, посчитаем (с помощью map/reduce) среднюю оценку по фильму.
# coding=utf-8
from pymongo import Connection
from pymongo.code import Code
# создадим соединение
connection = Connection('localhost', 5586)
# очистим БД
connection.drop_database('cinephiles')
# создадим БД
db = connection.cinephiles
# создадим коллекции для films и users
films = db.films
users = db.users
# создадим новые документы с данными о сущности 'Фильм'
films.insert([{'_id':1, 'title':'The Expendables', 'release':2010}, {'_id':2, 'title':'Iron Man 2', 'release':2010}, {'_id':3, 'title':'Prince of Persia', 'release':2010}])
# выведем список со всеми фильмами
for film in films.find():
print film
# создадим новые документы с данными о сущности 'Киноман'
users.insert({'name': 'John', 'films':[{'film':1, 'mark':3}, {'film':2, 'mark':5}, {'film':3, 'mark':5}]})
users.insert({'name': 'Jane', 'films':[{'film':1, 'mark':4}, {'film':2, 'mark':3}, {'film':3, 'mark':5}]})
users.insert({'name': 'Sali', 'films':[{'film':1, 'mark':5}, {'film':2, 'mark':2}, {'film':3, 'mark':5}]})
# посчитаем всех киноманов
film_count = films.count()
# подготовим данные для подсчета
map = Code(""" function() {
this.films.forEach(
function(x) {
emit(x.film, x.mark);
}
);
}""")
# посчитаем среднюю оценку по фильму
reduce = Code("""function (key, values) {
var sum = 0;
for(var mark in values) sum += values[mark];
return sum/%d;
}""" % film_count)
# выведем среднюю оценку по каждому фильму
result = db.users.map_reduce(map, reduce)
for mark in result.find():
print mark
Результат:
{u'release': 2010, u'_id': 1, u'title': u'The Expendables'}
{u'release': 2010, u'_id': 2, u'title': u'Iron Man 2'}
{u'release': 2010, u'_id': 3, u'title': u'Prince of Persia'}
{u'_id': 1.0, u'value': 1.3333333333333333}
{u'_id': 2.0, u'value': 1.1111111111111112}
{u'_id': 3.0, u'value': 1.6666666666666667}
Еще хороший пример с методами pymongo есть тут.
Использование с Django
Этот раздел тут упомяну лишь вскользь, более полный вариант будет в будущей заметке.
Мониторинг и администрирование
По-умолчанию с mongod стартует простой http-сервер, по тому же адресу что и сам mongod но порт на 1000 больше, чем порт самого mongod. Этот сервер предоставляет http интерфейс для просмотра базовой информации о сервере MongoDB. Вся представленная информация в простом веб-интерфейсе также может быть получена через shell, например текущую версию сервера, uptime и количество подключений можно узнать с помощью:
> db.runCommand({"serverStatus" : 1})
В базовой поставкой MongoDB есть консольная-команда mongostat - выводит ту же инфу что и serverStatus, но в более дружественном виде.
Для web-админимтрирования MongoDB есть Opricot, подробнее можете прочитать на домашней странице.
Репликации
Другие применения MongoDB
Map Reduce
Дополнительно чтиво