Сегодня мы рассмотрим интеграцию реляционной и нереляционной баз данных в одном приложении. Да, это как съесть одновременно пиццу и суши — звучит странно, но иногда просто не обойтись без такого сочетания.
Представьте себе крупное приложение электронной коммерции. У вас есть огромный каталог продуктов, информация о клиентах, заказы и платежи. Что хранить в PostgreSQL? Логично сохранить там транзакции, которые требуют строгой целостности. А MongoDB отлично подойдет для хранения отзывов пользователей на товары — они разнообразны по структуре и часто изменяются. В таких случаях комбинирование реляционных и нереляционных баз данных позволяет добиться одновременно надежности и гибкости.
Архитектура приложения с двумя базами данных
Когда мы говорим о проекте с интеграцией PostgreSQL и MongoDB, нам нужно учитывать следующий план:
- PostgreSQL для хранения структурированных и критически важных данных.
- MongoDB для хранения больших объемов неструктурированных данных.
- API-интерфейс для взаимодействия с обеими базами данных.
- Четкое распределение задач между базами данных.
Главные принципы такой архитектуры:
- Разделение ответственности: каждый тип данных обрабатывается в системе, наиболее подходящей для него.
- Синхронизация данных и их целостность: определите, где данные должны быть связаны и как обеспечить синхронность.
- Производительность: обеспечьте быстрый доступ к данным там, где это важно.
Установка и настройка приложения
Если у вас еще не установлены PostgreSQL и MongoDB, установите их. Для PostgreSQL можно использовать официальную документацию PostgreSQL, а для MongoDB — руководство по установке MongoDB.
Мы также будем использовать asyncpg и motor для работы с PostgreSQL и MongoDB через Python.
Установим необходимые зависимости:
pip install asyncpg motor fastapi uvicorn
В файле config.py определим параметры подключений для баз данных:
POSTGRES_URL = "postgresql://user:password@localhost:5432/mydb"
MONGO_URL = "mongodb://localhost:27017"
Создадим модуль для подключения к PostgreSQL:
import asyncpg
class PostgresConnection:
def __init__(self, dsn):
self.dsn = dsn
self.connection = None
async def connect(self):
self.connection = await asyncpg.connect(self.dsn)
async def disconnect(self):
if self.connection:
await self.connection.close()
postgres = PostgresConnection(dsn="postgresql://user:password@localhost:5432/mydb")
Создаем модуль для подключения к MongoDB:
from motor.motor_asyncio import AsyncIOMotorClient
class MongoDBConnection:
def __init__(self, url):
self.url = url
self.client = None
async def connect(self):
self.client = AsyncIOMotorClient(self.url)
self.database = self.client.mydb
async def disconnect(self):
if self.client:
self.client.close()
mongo = MongoDBConnection(url="mongodb://localhost:27017")
Работа с базами данных: примеры
Давайте представим, что наше приложение хранит данные о заказах в PostgreSQL и отзывы на товары в MongoDB.
Создадим таблицу заказов в PostgreSQL:
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
customer_name TEXT NOT NULL,
amount NUMERIC NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Добавим функцию для добавления заказа:
async def create_order(customer_name: str, amount: float):
query = "INSERT INTO orders (customer_name, amount) VALUES ($1, $2) RETURNING id;"
return await postgres.connection.fetchval(query, customer_name, amount)
Создадим функцию для чтения заказов:
async def get_orders():
query = "SELECT * FROM orders;"
return await postgres.connection.fetch(query)
Отзывы — это неструктурированные данные, поэтому MongoDB подойдет отлично. Например:
{
"product_id": "12345",
"review": "Отличный товар!",
"rating": 5,
"timestamp": "2023-10-03T12:00:00Z"
}
Добавим функцию для добавления отзыва:
async def add_review(review: dict):
return await mongo.database.reviews.insert_one(review)
Добавим функцию для получения отзывов о продукте:
async def get_reviews(product_id: str):
return await mongo.database.reviews.find({"product_id": product_id}).to_list(100)
Интеграция в FastAPI
Теперь объединим наши базы данных в API. В файле main.py:
from fastapi import FastAPI
from config import POSTGRES_URL, MONGO_URL
from databases import postgres, mongo, create_order, get_orders, add_review, get_reviews
app = FastAPI()
@app.on_event("startup")
async def startup():
await postgres.connect()
await mongo.connect()
@app.on_event("shutdown")
async def shutdown():
await postgres.disconnect()
await mongo.disconnect()
@app.post("/orders/")
async def create_new_order(customer_name: str, amount: float):
order_id = await create_order(customer_name, amount)
return {"id": order_id}
@app.get("/orders/")
async def list_orders():
orders = await get_orders()
return {"orders": orders}
@app.post("/reviews/")
async def create_review(review: dict):
result = await add_review(review)
return {"id": str(result.inserted_id)}
@app.get("/reviews/{product_id}")
async def list_reviews(product_id: str):
reviews = await get_reviews(product_id)
return {"reviews": reviews}
Запустим сервер:
uvicorn main:app --reload
Пример работы
- Создаем новый заказ:
POST /orders/
Ответ:{ "customer_name": "Иван Иванов", "amount": 1500.75 }{ "id": 1 } - Добавляем отзыв:
POST /reviews/
Ответ:{ "product_id": "12345", "review": "Прекрасный товар!", "rating": 5 }{ "id": "64f765ad7b8e5a192cfa3d73" } - Получаем список заказов:
GET /orders/Ответ:{ "orders": [ { "id": 1, "customer_name": "Иван Иванов", "amount": 1500.75, "created_at": "2023-10-03T14:00:00Z" } ] } - Получаем отзывы о продукте:
GET /reviews/12345Ответ:{ "reviews": [ { "product_id": "12345", "review": "Прекрасный товар!", "rating": 5, "timestamp": "2023-10-03T14:30:00Z" } ] }
Особенности и сложности
Работа с двумя базами данных может показаться сложной с точки зрения их синхронизации. Например, метаинформация из PostgreSQL может понадобиться в MongoDB. В таком случае лучше использовать фреймворки вроде Kafka для обеспечения событийной синхронизации, но это уже тема для другой лекции.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ