Основы базы данных MongoDB

Мы привыкли работать с реляционными базами данных, преимущественно с использованием языка SQL. Однако существует множество СУБД, не поддерживающих данную парадигму, так называемых NoSQL.  Может возникнуть вопрос, а зачем нужны такие СУБД? Давайте представим, что нам необходимо хранить базу разнообразных документов, причем у них могут быть разнообразные поля. В случае реляционной СУБД мы можем на каждый тип документов завести отдельную таблицу. Но что если существуют поля, которые могут отсутствовать у некоторых документов? В парадигме реакционных СУБД мы можем заполнять несуществующие поля значением NULL. Но что если у каждого документа может быть вообще разный состав полей, и это не разные типы документов, а все документы одного вида?

Давайте рассмотрим пример. Пусть нам необходимо хранить описания и рецептуру блюд. В парадигме реляционной СУБД мы будем создавать таблицу с перечнем блюд, и отдельную таблицу с рецептурой (перечень ингредиентов), которая связана с таблицей блюд отношением один ко многим. В таблице рецептуры у нас есть такие поля, как ингредиент, его количество, единица измерения. Эта таблица в свою очередь связана с таблицей ингредиентов отношением много ко многим. Но тут еще нужна таблица для единиц измерений. И вот у нас уже «зоопарк» связанных таблиц.

А теперь подумаем, как вся эта структура будет представлена в памяти компьютера. Если мы программируем в парадигме ООП, то у нас наверняка должна быть коллекция блюд, объект этой коллекции – блюдо, содержит коллекцию «рецептура», элемент которой содержат поле типа объект «ингредиент», количество, единицу измерения. Последнее тоже объект. А теперь представим, что у нас есть некий абстрактный класс «Единица измерения», от которого наследуется конкретная единица измерения. Аналогично и с ингредиентами. Разумеется, все поля классов замаплены на конкретные столбцы соответствующих объекту таблиц. Но что если в каком-нибудь дочернем классе появятся новые поля? Добавлять таблицы для этих классов, раздувать «зоопарк» таблиц еще больше?

Другой вариант архитектуры – это документоориентированная NoSQL СУБД, например, MongoDB. О ней и пойдет речь в этой статье. Я расскажу, как создать базу данных MongoDB и работать с ней средствами языка Python.

Итак, регистрируемся на сайте https://www.mongodb.com. Обратите внимание, из России этот сервис не работает, видимо из-за санкций, так что используйте прокси. Далее на закладке Database создадим новую базу данных:

Создадим новую базу данных MongoDB

База данных представлена в виде дерева, «листики» которого – это таблица. Если кликнуть по таблице, то можно увидеть ее содержимое:

Содержимое базы данных MongoDB

Как видим, документы, извлекаемые из базы данных, представляют собой JSON-объекты. Здесь же есть кнопки для создания и удаления объектов базы данных, кроме того, можно ввести фильтр для выборки данных.

Каким образом подключиться к базе данных через Python?

Для начала надо установить и подключить библиотеку pymongo. Это можно сделать через pip, введя вот такую команду в командную строку:

python -m pip install pymongo

Ну и можно пользоваться:

import pymongo
from pymongo.server_api import ServerApi

client = pymongo.MongoClient("Строка подключения", server_api=ServerApi('1'))
db = client.test

try:
    print("MongoDB version is %s" % client.server_info()['version'])
except pymongo.errors.OperationFailure as error:
    print(error)
    quit(1)

my_collection = db.foods
my_collection.delete_many({
    "calories": {
        "$lt": 300
    }
})

Сформировать строку подключения можно в браузере mongoDB, нажав на кнопочку «Connect»:

Формирование строки подключения в MongoDB

Откроется вот такое окно, там надо выбрать «Connect your application»:

Подключение в MongoDB

Выбираем язык Python:

Выбираем язык Python в MongoDB

И видим строку подключения:

Строка подключения в MongoDB

Копируем ее в программу, вместо <password> ставим ваш реальный пароль.

Чтобы создать новую таблицу, можно воспользоваться методов create_collection базы данных:

import pymongo
from pymongo.server_api import ServerApi

client = pymongo.MongoClient("mongodb+srv://megabax:<Пароль>@cluster0.vwremdq.mongodb.net/?retryWrites=true&w=majority", server_api=ServerApi('1'))
db = client.test

try:
    print("MongoDB version is %s" % client.server_info()['version'])
except pymongo.errors.OperationFailure as error:
    print(error)
    quit(1)

db.create_collection("MyTable")

После выполнения программы в списке таблиц базы данных появится наша таблица:

Таблица в базе данных MongoDB

В общих чертах, как работать с базой данных mongoDB. Как видим из примеров кода, сначала мы создаем подключение (клиента). Через него получаем объект базы данных (это поле объекта клиента, имя которого совпадает с именем базы данных). Сам объект базы данных содержит в себе поля, соответствующие таблицам. Эти таблицы представляют собой коллекцию элементов таблицы. Эти коллекции содержат в себе методы по манипулированию данными, такие как перебор элементов, поиск, добавление и удаление. Давайте, например, создадим тестовую базу данных, путем добавления в цикле множества элементов методом   insert_one:

import pymongo
from pymongo.server_api import ServerApi

import random
import string


def generate_random_string(length):
    letters = string.ascii_lowercase
    rand_string = ''.join(random.choice(letters) for i in range(length))
    print("Random string of length", length, "is:", rand_string)
    return rand_string

def get_random_features():
    dict={}
    ln=random.randint(1,10)
    for i in range(ln):
        dict["feature"+str(i)]=generate_random_string(random.randint(3,15))
    return dict

client = pymongo.MongoClient("mongodb+srv://megabax:<Пароль>@cluster0.vwremdq.mongodb.net/?retryWrites=true&w=majority", server_api=ServerApi('1'))
db = client.test

try:
    print("MongoDB version is %s" % client.server_info()['version'])
except pymongo.errors.OperationFailure as error:
    print(error)
    quit(1)


mongo_collection = db.goods


for i in range(100):
    mongo_collection.insert_one({
        "_id": i,
        "name": generate_random_string(random.randint(3,15)),
        "price": round(random.random()*100,2),
        "features": get_random_features(),
        "quantity": random.randint(1,10000)
    })

Теперь попробуем перебрать элементы таблицы:

import pymongo
from pymongo.server_api import ServerApi

client = pymongo.MongoClient("mongodb+srv://megabax:<Пароль>@cluster0.vwremdq.mongodb.net/?retryWrites=true&w=majority", server_api=ServerApi('1'))
db = client.test

try:
    print("MongoDB version is %s" % client.server_info()['version'])
except pymongo.errors.OperationFailure as error:
    print(error)
    quit(1)

my_collection = db.goods
my_cursor = my_collection.find()

for item in my_cursor:
    print(item["name"])

Этот код переберет все элементы, и выведет значения их полей name. Можно перебрать по фильтру:

my_cursor = my_collection.find({
    "name": "jgdpspvonpune"
})

Стоит заметить, что в качестве полей у элементов коллекции может быть и коллекция, и какой-либо другой объект. Например, у элемента коллекции goods есть элемент features, который сам по себе является объектом, а именно словарем:

Словарь в MongoDB

А сейчас мы сделаем следующее. Очистим коллекцию goods, а потом снова перезаполним ее, но немного по-другому. Для этого можно вызвать метод delete_many(), а в качестве параметров указать пустой фильтр:

import pymongo
from pymongo.server_api import ServerApi

client = pymongo.MongoClient("mongodb+srv://megabax:<Пароль>@cluster0.vwremdq.mongodb.net/?retryWrites=true&w=majority", server_api=ServerApi('1'))
db = client.test

try:
    print("MongoDB version is %s" % client.server_info()['version'])
except pymongo.errors.OperationFailure as error:
    print(error)
    quit(1)

my_collection = db.goods
my_collection.delete_many({})

Результатом работы скрипта будет полная очистка коллекции:

Очистка коллекции в MongoDB

Теперь поменяем в нашем скрипте формирования демо базы всего лишь одну функцию:

def get_random_features():
    list=[]
    ln=random.randint(1,10)
    for i in range(ln):
        list.append(generate_random_string(random.randint(3,15)))
    return list

Теперь вместо объекта в поле features у нас коллекция, а не объект:

Коллекция в MongoDB

И теперь мы можем осуществить поиск по элементу коллекции:

my_cursor = my_collection.find({
    "features": {"$eq": "hpwfslrwfsuqmue"}
})

Запрос найдет все документы, в которых в коллекции features встретится строка  «hpwfslrwfsuqmue».

У меня выдало:

xinfirdgftc

Проверим:

Проверка в MongoDB

Выражение $eq в фильтре означает «равно». Можно сравнивать на больше меньше, например, «меньше или равно» будет кодироваться как $lt:

import pymongo
from pymongo.server_api import ServerApi

client = pymongo.MongoClient("mongodb+srv://megabax:<Пароль>@cluster0.vwremdq.mongodb.net/?retryWrites=true&w=majority", server_api=ServerApi('1'))
db = client.test

try:
    print("MongoDB version is %s" % client.server_info()['version'])
except pymongo.errors.OperationFailure as error:
    print(error)
    quit(1)

my_collection = db.goods

my_cursor = my_collection.find({
    "price": {"$lt": 10}
})

for item in my_cursor:
    print(item["name"], item["price"])

Эта программа выдаст список товаров, цена которых не превышает 10.

Более подробно о фильтрах и прочих возможностях mongjDB можно прочитать в документации MongoDB Documentation.

Comments

So empty here ... leave a comment!

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

Sidebar