JavaRush /Курсы /Модуль 4: FastAPI /Пример работы с PostgreSQL и MongoDB в одном приложении

Пример работы с PostgreSQL и MongoDB в одном приложении

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

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

Представьте себе крупное приложение электронной коммерции. У вас есть огромный каталог продуктов, информация о клиентах, заказы и платежи. Что хранить в PostgreSQL? Логично сохранить там транзакции, которые требуют строгой целостности. А MongoDB отлично подойдет для хранения отзывов пользователей на товары — они разнообразны по структуре и часто изменяются. В таких случаях комбинирование реляционных и нереляционных баз данных позволяет добиться одновременно надежности и гибкости.


Архитектура приложения с двумя базами данных

Когда мы говорим о проекте с интеграцией PostgreSQL и MongoDB, нам нужно учитывать следующий план:

  1. PostgreSQL для хранения структурированных и критически важных данных.
  2. MongoDB для хранения больших объемов неструктурированных данных.
  3. API-интерфейс для взаимодействия с обеими базами данных.
  4. Четкое распределение задач между базами данных.

Главные принципы такой архитектуры:

  • Разделение ответственности: каждый тип данных обрабатывается в системе, наиболее подходящей для него.
  • Синхронизация данных и их целостность: определите, где данные должны быть связаны и как обеспечить синхронность.
  • Производительность: обеспечьте быстрый доступ к данным там, где это важно.

Установка и настройка приложения

Если у вас еще не установлены 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

Пример работы

  1. Создаем новый заказ:
    POST /orders/
    
    {
        "customer_name": "Иван Иванов",
        "amount": 1500.75
    }
    
    Ответ:
    
    {
        "id": 1
    }
    
  2. Добавляем отзыв:
    POST /reviews/
    
    {
        "product_id": "12345",
        "review": "Прекрасный товар!",
        "rating": 5
    }
    
    Ответ:
    
    {
        "id": "64f765ad7b8e5a192cfa3d73"
    }
    
  3. Получаем список заказов:
    GET /orders/ Ответ:
    
    {
        "orders": [
            {
                "id": 1,
                "customer_name": "Иван Иванов",
                "amount": 1500.75,
                "created_at": "2023-10-03T14:00:00Z"
            }
        ]
    }
    
  4. Получаем отзывы о продукте:
    GET /reviews/12345 Ответ:
    
    {
        "reviews": [
            {
                "product_id": "12345",
                "review": "Прекрасный товар!",
                "rating": 5,
                "timestamp": "2023-10-03T14:30:00Z"
            }
        ]
    }
    

Особенности и сложности

Работа с двумя базами данных может показаться сложной с точки зрения их синхронизации. Например, метаинформация из PostgreSQL может понадобиться в MongoDB. В таком случае лучше использовать фреймворки вроде Kafka для обеспечения событийной синхронизации, но это уже тема для другой лекции.

1
Задача
Модуль 4: FastAPI, 10 уровень, 4 лекция
Недоступна
Подключение к PostgreSQL и MongoDB
Подключение к PostgreSQL и MongoDB
1
Задача
Модуль 4: FastAPI, 10 уровень, 4 лекция
Недоступна
Создание таблицы и коллекции
Создание таблицы и коллекции
3
Опрос
Основные различия между SQL и NoSQL базами данных, 10 уровень, 4 лекция
Недоступен
Основные различия между SQL и NoSQL базами данных
Основные различия между SQL и NoSQL базами данных
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ