Интеграция MongoDB с Python с помощью PyMongo
Вступление
В этом посте мы погрузимся в MongoDB как хранилище данных с точки зрения Python. С этой целью мы напишем простой сценарий, чтобы продемонстрировать, чего мы можем достичь и какие выгоды мы можем извлечь из этого.
Веб-приложения, как и многие другие программные приложения, питаются данными. Организация и хранение этих данных важны, поскольку они диктуют, как мы взаимодействуем с различными приложениями, находящимися в нашем распоряжении. Вид обрабатываемых данных также может влиять на то, как мы осуществляем этот процесс.
Базы данных позволяют нам организовывать и хранить эти данные, а также контролировать, как мы храним, получаем доступ и защищаем информацию.
Базы данных NoSQL
Существует два основных типа баз данных – реляционные и нереляционные .
Реляционные базы данных позволяют нам хранить, получать доступ и манипулировать данными по отношению к другой части данных в базе данных. Данные хранятся в организованных таблицах со строками и столбцами с отношениями, связывающими информацию между таблицами. Для работы с этими базами данных мы используем Structured Query Language (SQL), а примеры включают MySQL и PostgreSQL .
Нереляционные базы данных хранят данные ни в реляционных, ни в табличных базах данных, как в реляционных базах данных. Они также называются базами данных NoSQL , поскольку мы не используем SQL для взаимодействия с ними.
Кроме того, базы данных NoSQL можно разделить на Key-Value stores , Graph stores , Column stores и Document Stores , под которые подпадает MongoDB.
MongoDB и когда его использовать
MongoDB-это хранилище документов и нереляционная база данных . Это позволяет нам хранить данные в коллекциях , которые состоят из документов .
В MongoDB документ представляет собой просто JSON-подобный двоичный формат сериализации , называемый a BONUS или Binary-JSON, и имеет максимальный размер 16 мегабайт. Это ограничение размера используется для обеспечения эффективного использования памяти и полосы пропускания во время передачи.
MongoDB также предоставляет спецификацию GridFS на случай, если возникнет необходимость хранить файлы размером больше установленного предела.
Документы состоят из пар “поле-значение”, как и в обычных данных JSON. Однако этот формат BSON также может содержать больше типов данных, таких как Date
types и Binary Data
types. BENSON был разработан, чтобы быть легким, легко проходимым и эффективным при кодировании и декодировании данных в BSON и из BSON.
Будучи хранилищем данных NoSQL, MongoDB позволяет нам пользоваться преимуществами, которые дает использование нереляционной базы данных по сравнению с реляционной. Одним из преимуществ является то, что он обеспечивает высокую масштабируемость за счет эффективного горизонтального масштабирования путем сегментирования или секционирования данных и размещения их на нескольких машинах.
MongoDB также позволяет хранить большие объемы структурированных, полуструктурированных и неструктурированных данных без необходимости поддерживать отношения между ними. Будучи открытым исходным кодом, стоимость внедрения MongoDB держится на низком уровне только за счет технического обслуживания и экспертных знаний.
Как и любое другое решение, использование MongoDB имеет свои недостатки. Первый из них заключается в том, что он не поддерживает отношений между хранящимися данными. Из-за этого трудно выполнять ACID-транзакции , которые обеспечивают согласованность.
Сложность увеличивается при попытке поддержать транзакции ACID. MongoDB, как и другие хранилища данных NoSQL, не так совершенен, как реляционные базы данных, и это может затруднить поиск экспертов.
Нереляционная природа MongoDB делает его идеальным для хранения данных в конкретных ситуациях по сравнению с его реляционными аналогами. Например, сценарий, в котором MongoDB более подходит, чем реляционная база данных, когда формат данных является гибким и не имеет никаких отношений.
С гибкими/нереляционными данными нам не нужно поддерживать свойства ACID при хранении данных, в отличие от реляционных баз данных. MongoDB также позволяет нам легко масштабировать данные в новые узлы.
Однако при всех своих преимуществах MongoDB не идеален, когда наши данные реляционны по своей природе. Например, если мы храним записи клиентов и их заказы.
В этой ситуации нам понадобится реляционная база данных для поддержания отношений между нашими данными, которые важны. Он также не подходит для использования MongoDB, если нам нужно соблюдать свойства КИСЛОТЫ.
Взаимодействие с MongoDB через оболочку Mongo
Для работы с MongoDB нам нужно будет установить сервер MongoDB , который мы можем скачать с официальной домашней страницы . Для этой демонстрации мы будем использовать бесплатный сервер сообщества.
Сервер MongoDB поставляется с оболочкой Mongo Shell , которую мы можем использовать для взаимодействия с сервером через терминал.
Чтобы активировать оболочку, просто введите mongo
в вашем терминале. Вас встретит информация о настройке сервера MongoDB, включая версию оболочки MongoDB и Mongo, а также URL-адрес сервера.
Например, наш сервер работает на:
mongodb://127.0.0.1:27017
В MongoDB база данных используется для хранения коллекций, содержащих документы. Через оболочку Mongo мы можем создать новую базу данных или переключиться на существующую с помощью команды use
:
> use SeriesDB
Каждая операция, которую мы выполняем после этого, будет выполняться в нашей базе данных Series DB
. В базе данных мы будем хранить коллекции, которые аналогичны таблицам в реляционных базах данных.
Например, для целей этого урока давайте добавим несколько серий в базу данных:
> db.series.insertMany([ ... { name: "Game of Thrones", year: 2012}, ... { name: "House of Cards", year: 2013 }, ... { name: "Suits", year: 2011} ... ])
Нас встречают с:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("5e300724c013a3b1a742c3b9"), ObjectId("5e300724c013a3b1a742c3ba"), ObjectId("5e300724c013a3b1a742c3bb") ] }
Чтобы извлечь все документы, хранящиеся в нашей коллекции series
, мы используем db.inventory.find ({})
, SQL-эквивалент которого равен SELECT * FROM series
. Передача пустого запроса (т. е. {}
) вернет все документы:
> db.series.find({}) { "_id" : ObjectId("5e3006258c33209a674d1d1e"), "name" : "The Blacklist", "year" : 2013 } { "_id" : ObjectId("5e300724c013a3b1a742c3b9"), "name" : "Game of Thrones", "year" : 2012 } { "_id" : ObjectId("5e300724c013a3b1a742c3ba"), "name" : "House of Cards", "year" : 2013 } { "_id" : ObjectId("5e300724c013a3b1a742c3bb"), "name" : "Suits", "year" : 2011 }
Мы также можем запросить данные, используя условие равенства, например, чтобы вернуть все телесериалы, премьера которых состоялась в 2013 году:
> db.series.find({ year: 2013 }) { "_id" : ObjectId("5e3006258c33209a674d1d1e"), "name" : "The Blacklist", "year" : 2013 } { "_id" : ObjectId("5e300724c013a3b1a742c3ba"), "name" : "House of Cards", "year" : 2013 }
Эквивалентом SQL будет SELECT * FROM series WHERE
.
MongoDB также позволяет нам обновлять отдельные документы с помощью db.collection.Update One ()
или выполните пакетное обновление с помощью db.collection.UpdateMany()
. Например, чтобы обновить год выпуска для Suits
:
> db.series.updateOne( { name: "Suits" }, { $set: { year: 2010 } } ) { "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
Наконец, для удаления документов оболочка Mongo предлагает db.collection.deleteOne()
и db.collection.удалить многие функции ()
.
Например, удалить все серии, премьера которых состоялась в 2012
, мы бы побежали:
> db.series.deleteMany({ year: 2012 }) { "acknowledged" : true, "deletedCount" : 2 }
Более подробную информацию об операциях CRUD на MongoDB можно найти в онлайн-справочнике включая дополнительные примеры, выполнение операций с условиями, атомарность и сопоставление концепций SQL с концепциями и терминологией MongoDB.
Интеграция Python с MongoDB
MongoDB предоставляет драйверы и инструменты для взаимодействия с хранилищем данных MongoDB с использованием различных языков программирования, включая Python, JavaScript, Java, Go и C#.
PyMongo – это официальный драйвер MongoDB для Python, и мы будем использовать его для создания простого скрипта, который будет использоваться для манипулирования данными, хранящимися в нашей базе данных SeriesDB
.
С помощью Python 3.6+ и Virtualenv , установленных на наших машинах, давайте создадим виртуальную среду для нашего приложения и установим PyMongo через pip:
$ virtualenv --python=python3 env --no-site-packages $ source env/bin/activate $ pip install pymongo
Использование PyMongo
, мы собираемся написать простой скрипт, который мы можем выполнить для выполнения различных операций с нашей базой данных MongoDB.
Подключение к MongoDB
Во-первых, мы импортируем pymongo
в наш mongo_db_script.py
и создайте клиент, подключенный к локально запущенному экземпляру MongoDB:
import pymongo # Create the client client = MongoClient('localhost', 27017) # Connect to our database db = client['SeriesDB'] # Fetch our series collection series_collection = db['series']
До сих пор мы создали клиент, который подключается к вашему серверу MongoDB и использует его для получения нашей базы данных “Series DB”. Затем мы извлекаем нашу коллекцию “серий” и храним ее в объекте.
Создание документов
Чтобы сделать наш скрипт более удобным, мы напишем функции, которые оборачиваются вокруг PyMongo
, чтобы мы могли легко манипулировать данными. Мы будем использовать Python словари для представления документов и передадим эти словари нашим функциям. Во-первых, давайте создадим функцию для вставки данных в нашу коллекцию “серий”:
# Imports truncated for brevity def insert_document(collection, data): """ Function to insert a document into a collection and return the document's id. """ return collection.insert_one(data).inserted_id
Эта функция получает коллекцию и словарь данных и вставляет данные в предоставленную коллекцию. Затем функция возвращает идентификатор, который мы можем использовать для точного запроса отдельного объекта из базы данных.
Следует также отметить, что MongoDB добавляет дополнительный ключ _id
к нашим документам, когда они не предоставляются, при создании данных.
Теперь давайте попробуем добавить шоу с помощью нашей функции:
new_show = { "name": "FRIENDS", "year": 1994 } print(insert_document(series_collection, new_show))
Выход таков:
5e4465cfdcbbdc68a6df233f
Когда мы запускаем наш скрипт, _id
нашего нового шоу печатается на терминале, и мы можем использовать этот идентификатор для получения шоу позже.
Мы можем предоставить значение _id
вместо того, чтобы назначать его автоматически, что мы бы предоставили в словаре:
new_show = { "_id": "1", "name": "FRIENDS", "year": 1994 }
И если бы мы попытались сохранить документ с существующим _id
, нас встретила бы ошибка, похожая на следующую:
DuplicateKeyError: E11000 duplicate key error index: SeriesDB.series.$id dup key: { : 1}
Извлечение Документов
Для извлечения документов из базы данных мы будем использовать find_document()
, который запрашивает нашу коллекцию для одного или нескольких документов. Наша функция получит словарь, содержащий элементы, по которым мы хотим отфильтровать, и необязательный аргумент, указывающий, хотим ли мы получить один документ или несколько документов:
# Imports and previous code truncated for brevity def find_document(collection, elements, multiple=False): """ Function to retrieve single or multiple documents from a provided Collection using a dictionary containing a document's elements. """ if multiple: results = collection.find(elements) return [r for r in results] else: return collection.find_one(elements)
А теперь давайте воспользуемся этой функцией, чтобы найти некоторые документы:
result = find_document(series_collection, {'name': 'FRIENDS'}) print(result)
При выполнении нашей функции мы не предоставили параметр multiple
, и в результате получился один документ:
{'_id': ObjectId('5e3031440597a8b07d2f4111'), 'name': 'FRIENDS', 'year': 1994}
Когда задан параметр multiple
, результатом будет список всех документов в нашей коллекции, для которых атрибут name
имеет значение FRIENDS
.
Обновление документов
Наша следующая функция, update_document()
, будет использоваться для обновления одного конкретного документа. Мы будем использовать _id
документа и коллекции, к которой он принадлежит, при его обнаружении:
# Imports and previous code truncated for brevity def update_document(collection, query_elements, new_values): """ Function to update a single document in a collection. """ collection.update_one(query_elements, {'$set': new_values})
Теперь давайте вставим документ:
new_show = { "name": "FRIENDS", "year": 1995 } id_ = insert_document(series_collection, new_show)
Сделав это, давайте обновим документ, который мы укажем с помощью _id
, возвращенного при его добавлении:
update_document(series_collection, {'_id': id_}, {'name': 'F.R.I.E.N.D.S'})
И, наконец, давайте выберем его, чтобы убедиться, что новое значение было введено на место, и напечатаем результат:
result = find_document(series_collection, {'_id': id_}) print(result)
Когда мы выполняем наш скрипт, мы видим, что наш документ был обновлен:
{'_id': ObjectId('5e30378e96729abc101e3997'), 'name': 'F.R.I.E.N.D.S', 'year': 1995}
Удаление документов
И наконец, давайте напишем функцию для удаления документов:
# Imports and previous code truncated for brevity def delete_document(collection, query): """ Function to delete a single document from a collection. """ collection.delete_one(query)
Поскольку мы используем метод delete_one
, за один вызов можно удалить только один документ, даже если запрос совпадает с несколькими документами.
Теперь давайте используем эту функцию для удаления записи:
delete_document(series_collection, {'_id': id_})
Если мы попытаемся получить тот же самый документ:
result = find_document(series_collection, {'_id': id_}) print(result)
Нас встречают с ожидаемым результатом:
None
Следующие Шаги
Мы выделили и использовали несколько методов PyMongo
для взаимодействия с нашим сервером MongoDB из скрипта Python. Однако мы не использовали все методы, доступные нам через модуль.
Все доступные методы можно найти в официальной документации PyMongo и классифицируются в соответствии с подмодулями.
Мы написали простой скрипт, который выполняет элементарную функциональность CRUD в базе данных MongoDB. Хотя мы могли бы импортировать функции в более сложную кодовую базу или, например, в приложение Flask/Django, эти фреймворки уже имеют библиотеки для достижения тех же результатов. Эти библиотеки делают его проще, удобнее и помогают нам более надежно подключаться к MongoDB.
Например, с Django мы можем использовать такие библиотеки , как Django MongoDB Engine и Djongo , в то время как Flask имеет Flask-PyMongo , который помогает преодолеть разрыв между Flask и PyMongo для облегчения бесшовного подключения к базе данных MongoDB.
Вывод
MongoDB-это хранилище документов, которое относится к категории нереляционных баз данных (NoSQL). Он имеет определенные преимущества по сравнению с реляционными базами данных, а также некоторые недостатки.
Хотя он не подходит для всех ситуаций, мы все еще можем использовать MongoDB для хранения данных и манипулирования данными из наших приложений Python с помощью PyMongo
среди других библиотек – позволяет нам использовать мощь MongoDB в ситуациях, когда он лучше всего подходит.
Поэтому мы должны тщательно изучить ваши требования, прежде чем принимать решение об использовании MongoDB для хранения данных.
Сценарий, который мы написали в этом посте, можно найти на GitHub .