Сегодня мы углубимся в концепцию коллекций и документов в 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, она либо:
- Ищет результат с использованием индекса (быстро), либо
- Проводит полный обход всех документов в коллекции (медленно, если коллекция большая).
Пример индексации:
# Создаём индекс на поле '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.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ