Рубрики
Без рубрики

Объявление Beanie – MongoDB ODM

ПРЕДУПРЕЖДЕНИЕ!! Эта статья устарела. Пожалуйста, следуйте текущей документации Beanie, чтобы использовать актуальные … Помечено с Python, Mongodb, Beanie.

ПРЕДУПРЕЖДЕНИЕ!! Эта статья устарела. Пожалуйста, следуйте текущей документации Bebie, чтобы использовать фактические функции и узоры. Ссылка на DOC – https://roman-right.github.io/beanie/

Я взволнован, чтобы представить Beanie – Python Micro ODM (объектный документ Mapper) для MongoDB!

Основной компонент Beanie является Pydantic – популярная библиотека для анализа и проверки данных. Это помогает реализовать основную функцию – структурирование данных. Beanie Документ – абстракция над пидантическими Базомодель Это позволяет работать с объектами Python на уровне приложения и объектам JSON на уровне базы данных. В общем случае одна коллекция Mongodb связана с одной Beanie Документ Отказ Это приносит предсказуемость при работе с базой данных, и в то же время сохраняет всю гибкость документов MongoDB – можно представлять любую структуру данных с Pступайской моделью (или даже группой структур с дополнительными и объединительными аннотациями).

Я делаю несколько нескольких проектов для домашних животных: эксперименты с новыми технологиями и доказательствами концепций. Для этих целей мне нужен инструмент для работы с базой данных, которую я могу использовать немедленно без длительной настройки. И с помощью которого я мог бы часто изменить структуру данных, добавлять и падать элементы здесь и там. Вот как родился Beanie.

Пример использования

Но это немного скучно, не так ли? Теперь давайте доберемся до интересной части – примеры использования. Это покажет, насколько удобно этот инструмент. Я намеренно пропускаю дополнительный импорт и помощники здесь, чтобы не перегружать картинку и фокусироваться только на важных вещах. Все рабочие приложения из этой статьи в моем репо GitHub Beanie-Fastapi-Demo Отказ

В качестве примера я создам небольшой отдых для управления заметками.

Установка

pip install beanie

ИЛИ

poetry add beanie

Модель данных

Пакет установлен. Теперь мы готовы пойти. Давайте определим структуру примечаний.

from enum import Enum
from typing import Optional, List

from beanie import Document
from pydantic import BaseModel


class TagColors(str, Enum):
    RED = "RED"
    BLUE = "BLUE"
    GREEN = "GREEN"


class Tag(BaseModel):
    name: str
    color: TagColors = TagColors.BLUE


class Note(Document):  # This is the document structure
    title: str
    text: Optional[str]
    tag_list: List[Tag] = []

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

Теперь я создадим соединение базы данных и инициализацию Beanie:

import motor.motor_asyncio
from beanie.general import init_beanie


async def main():
    # Create Motor client
    client = motor.motor_asyncio.AsyncIOMotorClient(
        f"mongodb://user:pass@host:27017/beanie_db"
    )

    # Init Beanie
    await init_beanie(client.beanie_db, document_models=[Note])

Никаких сюрпризов здесь. Beanie использует мотор как асинхронный драйвер для MongoDB. Для инициализации мне необходимо предоставить список всех документов Beanie, с которыми я буду работать.

веб приложение

Поскольку Framework API я буду использовать популярные Fastapi.

from fastapi import FastAPI

app = FastAPI()
app.include_router(notes_router, prefix="/v1", tags=["notes"])

Сначала я буду реализовывать простой Crud, чтобы показать основы beanie

Создавать

Перед любой реализацией конечной точки я хотел бы показать, как создать документ:

note = Note(title="Monday", text="What a nice day!")
await note.create()

Создать Способ хранит документ в базе данных. Кроме того, Beanie позволяет вводить документы в несколько других способов, включая пакетную вставку. Примеры использования можно найти в Документ Описания методов ссылка на сайт

Теперь я продемонстрирую ту же трюк, но на этот раз внутри конечной точки:

from fastapi import APIRouter

notes_router = APIRouter()


@notes_router.post("/notes/", response_model=Note)
async def create_note(note: Note):
    # Note creation
    await note.create()

    return note

Нажмите, чтобы увидеть информацию о запросе Пост || localhost: 10001/V1/Notes Вход: Введите полноэкранный режим Выйдите из полноэкранного режима Вывод: Введите полноэкранный режим Выйдите из полноэкранного режима

Fastapi использует пидантические модели для анализа тела запроса. Это означает, что я могу использовать Beanie Документ в качестве модели, а затем работают с уже проанализированным документом. Чтобы вставить его в базу данных, я использую Создать метод снова.

Читать

В ответ он возвращается _id – Уникальный идентификатор документа в базе данных. Теперь я покажу, как получить записку на основе его идентификатора.

Независимая реализация:

note = await Note.get(note_id)

Внутри конечной точки:

from beanie.fields import PydanticObjectId


# Helper method to get instances
async def get_note(note_id: PydanticObjectId) -> Note:
    # Note retrieval
    note = await Note.get(note_id)

    if note is None:
        raise HTTPException(
            status_code=404,
            detail="Note not found"
        )
    return note


# Actual endpoint
@notes_router.get("/notes/{note_id}", response_model=Note)
async def get_note_by_id(
        # Helper usage with Depends annotation
        note: Note = Depends(get_note)
):
    return note

Нажмите, чтобы увидеть информацию о запросе Получить || localhost: 10001/V1/Notes/60425951DedDed355386e0666ed Вывод: Введите полноэкранный режим Выйдите из полноэкранного режима

Обновлять

Приложение уже может создавать и прочитать заметки, но он еще ничего не может сделать с тегами. Это то, что я собираюсь сделать дальше.

Независимая реализация:

tag = Tag(name="false", color="RED")
await note.update(
    update_query={"$push": {"tag_list": tag.dict()}}
)

Внутри конечной точки:

@notes_router.put("/notes/{note_id}/add_tag", response_model=Note)
async def add_tag(tag: Tag, note: Note = Depends(get_note)):
    # Update the note
    await note.update(
        update_query={"$push": {"tag_list": tag.dict()}}
    )

    return note

Нажмите, чтобы увидеть информацию о запросе Поставить || localhost: 10001/V1/Notes/60425951DedDed355386e0666ed/add_tag Вход: Введите полноэкранный режим Выйдите из полноэкранного режима Вывод: Введите полноэкранный режим Выйдите из полноэкранного режима

Есть два основных типа Beanie Документ Обновить:

  • заменить – полное обновление документа
  • Обновление – Частичное обновление документа

Заменить полезен во многих случаях, но в текущем, я не знаю, если Примечание Документ сейчас находится в фактическом состоянии. Некоторые теги могут быть добавлены после последней синхронизации с базой данных. Если я заменил документ новыми данными, я могу легко потерять некоторые данные. Вот почему я использую частичное обновление здесь. Как аргумент, Обновление Метод принимает запрос в формате запроса Pymongo.

Удалить

Операция удаления не так интересно говорить о.

Независимая реализация:

await note.delete()

Внутри конечной точки:

@notes_router.delete("/notes/{note_id}", response_model=StatusModel)
async def get_note_by_id(note: Note = Depends(get_note)):
    # Delete the note
    await note.delete()

    return StatusModel(status=Statuses.DELETED)

Нажмите, чтобы увидеть информацию о запросе Удалить || localhost: 10001/V1/Notes/60425951DedDed355386e0666ed Вывод: Введите полноэкранный режим Выйдите из полноэкранного режима

Списки

Crud производится, но никакой услуги не получают конечных точек списка. Реализация снова проста.

Независимая реализация:

all_notes = await Note.find_all().to_list()
red_notes = Note.find_many({"tag_list.color": "RED"}).to_list()

Внутри конечной точки:

@notes_router.get(
    "/notes/",
    response_model=List[Note]
)
async def get_all_notes():
    # Get all notes
    return await Note.find_all().to_list()


@notes_router.get(
    "/notes/by_tag/{tag_name}",
    response_model=List[Note]
)
async def filter_notes_by_tag(tag_name: str):
    # Filter notes
    return await Note.find_many(
        {"tag_list.name": tag_name}
    ).to_list()

Нажмите, чтобы увидеть информацию о запросе Получить || localhost: 10001/V1/Notes Вывод: Введите полноэкранный режим Выйдите из полноэкранного режима Получить || localhost: 10001/V1/Notes/by_tag/истинный Вывод: Введите полноэкранный режим Выйдите из полноэкранного режима

Find_all Способ рассказывает все о себе по имени только. Find_Many также просто. Требуется запрос Пимонго в качестве аргумента для фильтрации документов.

Агрегаты

И, наконец, я хочу показать, как создавать агрегации с Beanie. В этом примере я рассчитаю, сколько заметок у меня на имя тега.

Независимая реализация:

class AggregationResponseItem(BaseModel):
    id: str = Field(None, alias="_id")
    total: int


results = await Note.aggregate(
    aggregation_query=[
        {"$unwind": "$tag_list"},
        {"$group": {
            "_id": "$tag_list.name",
            "total": {"$sum": 1}
        }}
    ],
    item_model=AggregationResponseItem
).to_list()

Внутри конечной точки:

@notes_router.get("/notes/aggregate/by_tag_name", response_model=List[AggregationResponseItem])
async def filter_notes_by_tag_name():
    # Notes aggregation
    return await Note.aggregate(
        aggregation_query=[
            {"$unwind": "$tag_list"},
            {"$group": {
                "_id": "$tag_list.name",
                "total": {"$sum": 1}
            }}
        ],
        item_model=AggregationResponseItem
    ).to_list()

Нажмите, чтобы увидеть информацию о запросе Получить || localhost: 10001/V1/Notes/Aggregate/by_tag_name Вывод: Введите полноэкранный режим Выйдите из полноэкранного режима

Во всех примерах до агрегации результат Примечание Методы были Примечание Объекты или списки Примечание объекты. Но в случае агрегации результат может иметь какую-либо структуру. Чтобы продолжить работу с объектами Python, которую я предоставляю параметр item_model = агрегацияseponseTem к совокупность метод И это возвращает список Агрегация реагировать объекты.

Вывод

Ну, обслуживание сделано. Я показал, насколько легко делать вещи с Beanie. Вы можете перестать думать о разборке и проверке данных базы данных и просто сосредоточиться на вашем проекте. Конечно, я не использовал все возможные функции. Вы можете найти весь список методов в описании проекта здесь

Beanie стала очень важной частью моего набора инструментов развития. Особенно когда дело доходит до создания прототипов. И я рад поделиться этим с сообществом. Я продолжаю использовать его в моих проектах – что означает, что я продолжаю развивать его. Следующая большая вещь, которую я хочу реализовать, – это структура и миграции данных.

Вы всегда можете привлечь участие в разработке:-) Спасибо вам большое за ваше время!

Ссылки на проект GitHub и Pypi:

Демо-проект из этой статьи:

Оригинал: “https://dev.to/romanright/announcing-beanie-mongodb-odm-56e”