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.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ