JavaRush /Курсы /Модуль 4: FastAPI /Работа с коллекциями и документами MongoDB

Работа с коллекциями и документами MongoDB

Модуль 4: FastAPI
8 уровень , 6 лекция
Открыта

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


Коллекции и документы: понятия и структура

Мы уже говорили о том, что MongoDB — документоориентированная база данных. Это означает, что данные хранятся не в виде таблиц, как в реляционных базах, а в виде коллекций документов. Коллекции — это по сути контейнеры (аналог таблиц в SQL), которые хранят документы.

Документы в MongoDB представляют собой данные в формате BSON (Binary JSON). Это расширение JSON, поддерживающее дополнительные типы данных, такие как int, datetime и др., что делает его очень удобным для программной обработки.

Пример документа:


{
    "_id": "63e8c0c89f1b5f001c854e4b",
    "name": "Alice",
    "email": "alice@example.com",
    "age": 30,
    "created_at": "2023-10-31T12:00:00Z"
}

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

Коллекции не требуют строгой схемы. Это значит, что два документа внутри одной коллекции могут иметь разную структуру:


{
    "_id": "63e8c0c89f1b5f001c854e4c",
    "name": "Bob",
    "phone": "+123456789"
}

Интересный факт: отсутствие строгой схемы не означает, что данные не имеют структуры. Обычно приложения всё равно накладывают бизнес-логику на хранимые данные.


Взаимодействие с коллекциями

Работа с коллекциями в MongoDB в основном сводится к использованию методов для создания, чтения, обновления и удаления документов (CRUD), которые мы уже знаем. Однако есть несколько важных моментов:

  • Создание коллекции. MongoDB автоматически создаёт коллекцию, как только вы добавляете в неё первый документ. Это упрощает начальную настройку.
  • Переименование. Коллекцию можно переименовать, сохранив её содержимое.
  • Удаление. Удалить коллекцию можно, но только с явным подтверждением. Это нечто вроде "случайно не нажал на rm -rf /?"

Пример в Python для создания и удаления коллекции:


from motor.motor_asyncio import AsyncIOMotorClient

client = AsyncIOMotorClient("mongodb://localhost:27017")
db = client.test_database

# Коллекция создаётся автоматически
collection = db.my_collection

# Удаление коллекции
await collection.drop()

Индексация данных в MongoDB

Индексы в MongoDB, как и в реляционных базах, используются для ускорения поиска данных. Они создаются на основе одного или нескольких полей документа в коллекции.

Когда вы создаёте запрос к MongoDB, она либо:

  1. Ищет результат с использованием индекса (быстро), либо
  2. Проводит полный обход всех документов в коллекции (медленно, если коллекция большая).

Пример индексации:


# Создаём индекс на поле 'email'
await collection.create_index("email", unique=True)

Виды индексов

MongoDB поддерживает несколько видов индексов:

  • Одиночные индексы (single field index) — для одного поля.
  • Составные индексы (compound index) — для нескольких полей.
  • Текстовые индексы (text index) — для полнотекстового поиска.
  • Уникальные индексы (unique index) — для обеспечения уникальности значений.

Пример создания составного индекса:


# Индекс для комбинации 'name' + 'email'
await collection.create_index([("name", 1), ("email", -1)])

Здесь 1 и -1 означают сортировку (1 — по возрастанию, -1 — по убыванию).

Чтобы просмотреть все индексы коллекции, используйте:


indexes = await collection.index_information()
print(indexes)

Обеспечение целостности данных

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

Пример транзакции:


async with client.start_session() as session:
    async with session.start_transaction():
        await collection1.insert_one({"_id": 1, "name": "Alice"}, session=session)
        await collection2.delete_one({"_id": 1}, session=session)

Если что-то пойдёт не так, транзакция будет откатана.


Работа с ACID

MongoDB поддерживает основное свойство ACID:

  • Atomicity (атомарность): все операции внутри транзакции выполняются или не выполняются вовсе.
  • Consistency (согласованность): после выполнения транзакции база остаётся в согласованном состоянии.
  • Isolation (изоляция): изменения, сделанные транзакцией, видимы только этой транзакции, пока она не завершена.
  • Durability (долговечность): после завершения транзакции её изменения гарантированно сохраняются.

Пример работы с коллекциями в реальном приложении

Создадим приложение на FastAPI для работы с коллекцией пользователей. Реализуем базовый CRUD API.


from fastapi import FastAPI, HTTPException
from motor.motor_asyncio import AsyncIOMotorClient
from bson import ObjectId

app = FastAPI()
client = AsyncIOMotorClient("mongodb://localhost:27017")
db = client.my_database
users_collection = db.users

# Вспомогательная функция для преобразования ObjectId в строку
def user_helper(user):
    return {
        "id": str(user["_id"]),
        "name": user["name"],
        "email": user["email"]
    }

@app.get("/users")
async def get_all_users():
    users = await users_collection.find().to_list(100)
    return [user_helper(user) for user in users]

@app.post("/users")
async def create_user(user: dict):
    result = await users_collection.insert_one(user)
    created_user = await users_collection.find_one({"_id": result.inserted_id})
    return user_helper(created_user)

@app.get("/users/{user_id}")
async def get_user(user_id: str):
    user = await users_collection.find_one({"_id": ObjectId(user_id)})
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user_helper(user)

@app.put("/users/{user_id}")
async def update_user(user_id: str, updated_data: dict):
    result = await users_collection.update_one({"_id": ObjectId(user_id)}, {"$set": updated_data})
    if result.modified_count == 0:
        raise HTTPException(status_code=404, detail="User not found")
    return {"msg": "User updated successfully"}

@app.delete("/users/{user_id}")
async def delete_user(user_id: str):
    result = await users_collection.delete_one({"_id": ObjectId(user_id)})
    if result.deleted_count == 0:
        raise HTTPException(status_code=404, detail="User not found")
    return {"msg": "User deleted successfully"}

Этот API позволит:

  • Добавлять новых пользователей.
  • Извлекать список пользователей.
  • Получать данные о конкретном пользователе.
  • Обновлять информацию.
  • Удалять пользователя.

MongoDB позволяет гибко и производительно работать с коллекциями и документами, что делает её отличным выбором для современных проектов. В следующей лекции мы рассмотрим ещё более продвинутые техники работы с MongoDB и FastAPI.

1
Задача
Модуль 4: FastAPI, 8 уровень, 6 лекция
Недоступна
Найти документы с фильтрацией
Найти документы с фильтрацией
1
Задача
Модуль 4: FastAPI, 8 уровень, 6 лекция
Недоступна
Создание индекса и работа с ним
Создание индекса и работа с ним
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ