Продолжаем наше увлекательное путешествие в мир MongoDB и баз данных NoSQL.
На прошлых лекциях мы познакомились с основами MongoDB: разобрали её архитектуру, возможности и научились подключать её к нашим проектам.
Сегодня настало время погрузиться в самую суть работы с MongoDB — основные операции с данными.
Говоря проще, научимся создавать, читать, обновлять и удалять данные (CRUD-операции).
CRUD — это основа основ при работе с любой базой данных. MongoDB предлагает весьма гибкий и лаконичный интерфейс для работы с данными.
CRUD расшифровывается как:
- Create (создание) — добавление новых данных (документов) в коллекцию.
- Read (чтение) — извлечение данных из коллекции.
- Update (обновление) — изменение существующих данных.
- Delete (удаление) — удаление данных.
Давайте по порядку разберём каждую операцию.
1. Создание (Create)
Добавить данные в MongoDB можно с помощью методов insert_one и insert_many.
Пример: добавление одного документа.
Метод insert_one позволяет добавить один документ в коллекцию.
from motor.motor_asyncio import AsyncIOMotorClient
from fastapi import FastAPI
app = FastAPI()
# Подключение к MongoDB
client = AsyncIOMotorClient("mongodb://localhost:27017")
db = client.my_database
collection = db.my_collection
@app.post("/create")
async def create_document():
document = {"name": "Alice", "age": 25, "city": "Wonderland"}
result = await collection.insert_one(document)
return {"inserted_id": str(result.inserted_id)}
👉 Обратите внимание: MongoDB автоматически добавляет поле _id, если вы его не указали. Это уникальный идентификатор документа.
Давайте в следующем примере добавим сразу несколько документов.
Для этого пригодится метод insert_many.
@app.post("/create_many")
async def create_many_documents():
documents = [
{"name": "Bob", "age": 30, "city": "Atlantis"},
{"name": "Charlie", "age": 28, "city": "Springfield"}
]
results = await collection.insert_many(documents)
return {"inserted_ids": [str(id) for id in results.inserted_ids]}
2. Чтение (Read)
Самая популярная операция — достать данные из базы. MongoDB предоставляет несколько методов для чтения данных, включая find_one и find.
Метод find_one позволяет извлечь первый подходящий документ.
@app.get("/read_one")
async def read_one_document():
result = await collection.find_one({"name": "Alice"})
return result
👉 Полезный факт: Возвращаемый документ — это просто словарь Python. Удобно, правда?
Ну а метод find возвращает все документы, соответствующие указанным критериям.
@app.get("/read_many")
async def read_many_documents():
cursor = collection.find({"age": {"$gt": 20}}) # Документы, где age > 20
results = []
async for document in cursor:
results.append(document)
return results
MongoDB поддерживает множество операторов для фильтрации данных:
$gtи$gte: больше и больше или равно.$ltи$lte: меньше и меньше или равно.$eqи$ne: равно и не равно.$inи$nin: входит или не входит в массив.
Пример фильтрации с несколькими условиями:
criteria = {"age": {"$gt": 20}, "city": "Springfield"}
3. Обновление (Update)
Для изменения существующих данных используются методы update_one, update_many и replace_one.
Метод update_one обновляет первый найденный документ.
@app.put("/update_one")
async def update_one_document():
filter = {"name": "Alice"}
update = {"$set": {"age": 26}}
result = await collection.update_one(filter, update)
return {"matched_count": result.matched_count, "modified_count": result.modified_count}
👉 Важно: мы используем оператор $set, чтобы указать, какие поля нужно обновить.
Метод update_many обновляет все документы, соответствующие фильтру.
@app.put("/update_many")
async def update_many_documents():
filter = {"city": "Wonderland"}
update = {"$set": {"city": "Neverland"}}
result = await collection.update_many(filter, update)
return {"matched_count": result.matched_count, "modified_count": result.modified_count}
Если вы хотите заменить документ полностью, то используйте метод replace_one.
@app.put("/replace_one")
async def replace_one_document():
filter = {"name": "Charlie"}
new_document = {"name": "Charlie", "age": 35, "country": "USA"}
result = await collection.replace_one(filter, new_document)
return {"matched_count": result.matched_count, "modified_count": result.modified_count}
4. Удаление (Delete)
Методы delete_one и delete_many выполняют удаление данных.
Метод delete_one удаляет первый подходящий документ.
@app.delete("/delete_one")
async def delete_one_document():
filter = {"name": "Alice"}
result = await collection.delete_one(filter)
return {"deleted_count": result.deleted_count}
Метод delete_many удаляет все документы, соответствующие фильтру.
@app.delete("/delete_many")
async def delete_many_documents():
filter = {"city": "Neverland"}
result = await collection.delete_many(filter)
return {"deleted_count": result.deleted_count}
Ошибки и особенности при работе с CRUD
- Отсутствие схемы: MongoDB не требует указания схемы для данных, что может привести к неструктурированным данным. Следите за консистентностью данных вручную или используйте валидацию на уровне приложения.
- Идентификатор
_id: значение_idдолжно быть уникальным. Если вы пытаетесь добавить документ с уже существующим_id, получите ошибку. - Пустой фильтр: если вы передадите пустой фильтр в
delete_manyилиupdate_many, все документы в коллекции будут затронуты. Это популярная ошибка новичков.
Практика: создаем приложение для управления пользователями
Давайте быстро соберем API, позволяющее управлять коллекцией пользователей.
У нас будут маршруты для создания, чтения, обновления и удаления пользователей.
@app.post("/users")
async def create_user(user: dict):
result = await collection.insert_one(user)
return {"inserted_id": str(result.inserted_id)}
@app.get("/users")
async def read_users():
cursor = collection.find({})
users = await cursor.to_list(length=100)
return users
@app.put("/users/{user_id}")
async def update_user(user_id: str, user: dict):
filter = {"_id": user_id}
update = {"$set": user}
result = await collection.update_one(filter, update)
return {"modified_count": result.modified_count}
@app.delete("/users/{user_id}")
async def delete_user(user_id: str):
filter = {"_id": user_id}
result = await collection.delete_one(filter)
return {"deleted_count": result.deleted_count}
Эти маршруты помогут вам лучше понять CRUD-операции на практике.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ