Beanie ODM Documentation

repository·main·Indexed 25 days ago

https://github.com/beanieodm/beanie

An asynchronous Python Object-Document Mapper (ODM) for MongoDB that leverages Pydantic for type-safe data modeling. Beanie provides support for CRUD operations, document relationships via Link and BackLink, lifecycle hooks, bulk writes, and TimeSeries collections. It includes a CLI for managing database migrations and a comprehensive set of find and update operators for complex MongoDB queries.

Tokens
21.8K
Snippets
79
Records
131
Agent score
83%

What's inside Beanie

  1. Use lazy parsing in queries to optimize performance

    main

    Lazy parsing allows you to skip the upfront parsing and validation process for documents. Instead, validation is performed on demand for each field individually when it is accessed. This can improve performance by reducing initial processing overhead, though it may introduce slight overhead during field access later.

    await Sample.find(Sample.number == 10, lazy_parse=True).to_list()
  2. Delete a single document

    main

    You can delete a single document in Beanie using two methods:

    1. Directly from a query: Use find_one() with a filter and call .delete() on the resulting object.
    2. From an existing instance: If you already have a document instance, call .delete() directly on that instance.

    Both methods are asynchronous and must be awaited.

    # Method 1: Delete directly from a query
    await Product.find_one(Product.name == "Milka").delete()
    
    # Method 2: Delete an existing instance
    bar = await Product.find_one(Product.name == "Milka")
    await bar.delete()
  3. Configure a Time Series collection in Beanie

    main

    To create a MongoDB time series collection, define a TimeSeriesConfig object within the Settings inner class of your Document.

    Compatibility Requirements:

    • Time series collections require MongoDB 5.0 or higher.
    • The fields bucket_max_span_seconds and bucket_rounding_seconds require MongoDB 6.3 or higher.

    The TimeSeriesConfig fields map directly to MongoDB's time series creation parameters.

    from datetime import datetime
    from beanie import Document, TimeSeriesConfig, Granularity
    from pydantic import Field
    
    class Sample(Document):
        ts: datetime = Field(default_factory=datetime.now)
        meta: str
    
        class Settings:
            timeseries = TimeSeriesConfig(
                time_field="ts",             # Required
                meta_field="meta",           # Optional
                granularity=Granularity.hours, # Optional
                bucket_max_span_seconds=3600,  # Optional (Requires MongoDB 6.3+)
                bucket_rounding_seconds=3600,  # Optional (Requires MongoDB 6.3+)
                expire_after_seconds=2        # Optional
            )
  4. Configure MongoDB for Beanie development

    main

    To run tests or use Beanie during development, you need an accessible MongoDB database.

    • Standard usage/tests: Assume a local database hosted on port 27017 without authentication.
    • Migrations: Requires a connection to a Replica Set or a Mongos instance.
  5. Define a Beanie Document

    main

    To map and handle data from a MongoDB collection, inherit from the Document class. Since Document inherits from Pydantic's BaseModel, it supports standard Pydantic data typing and parsing. You can use an inner Settings class to configure collection-specific metadata like names and indexes.

    from typing import Optional
    import pymongo
    from pydantic import BaseModel
    from beanie import Document, Indexed
    
    class Category(BaseModel):
        name: str
        description: str
    
    class Product(Document):
        name: str
        description: Optional[str] = None
        price: Indexed(float, pymongo.DESCENDING)
        category: Category
    
        class Settings:
            name = "products"
            indexes = [
                [
                    ("name", pymongo.TEXT),
                    ("description", pymongo.TEXT),
                ],
            ]
  6. Preview documentation changes

    main

    Beanie documentation is generated using pydoc-markdown (which uses mkdocs internally). To preview your documentation edits locally, run the pydoc-markdown server and visit the provided address (typically http://localhost:8000).

    Note: API documentation is automatically generated from source docstrings, while other documentation is written manually.

    pydoc-markdown --server
  7. Delete documents

    main

    To remove documents from the database, call the .delete() method on a found document or on a query result.

    # Delete a specific document instance
    bar = await Product.find_one(Product.name == "Milka")
    await bar.delete()
    
    # Delete via query
    await Product.find_one(Product.name == "Milka").delete()
    await Product.find(Product.category.name == "Chocolate").delete()
  8. Prepare a new version PR for Beanie

    main

    To prepare a new version of Beanie, you must create a Pull Request that updates the versioning across multiple files and generates an updated changelog.

    1. Update pyproject.toml: Change the version field to the new version number.
    2. Update beanie/__init__.py: Change the __version__ variable to the new version number.
    3. Update Changelog:
      • Edit scripts/generate_changelog.py to set current_version and new_version.
      • Run the generation script (see 'Generate the changelog' below).
      • Copy the output into the top of docs/changelog.md.
    4. Submit PR: Create a PR with a descriptive title and ensure all CI checks pass.
  9. Set up multi-field indexes via the Settings class

    main

    For complex or multi-field indexes, use the indexes list within the document's inner Settings class. The indexes list supports three formats:

    1. Single key: A string representing the field name (equivalent to Indexed()).
    2. List of (key, direction) pairs: A list of tuples where the first element is the field name (string) and the second is a PyMongo direction (e.g., pymongo.ASCENDING).
    3. pymongo.IndexModel instance: The most flexible option, allowing full access to PyMongo's indexing capabilities.
    import pymongo
    from pymongo import IndexModel
    from beanie import Document
    
    class Sample(Document):
        test_int: int
        test_str: str
    
        class Settings:
            indexes = [
                "test_int",  # Single key
                [
                    ("test_int", pymongo.ASCENDING),
                    ("test_str", pymongo.DESCENDING),
                ],  # List of (key, direction) pairs
                IndexModel(
                    [("test_str", pymongo.DESCENDING)],
                    name="test_string_index_DESCENDING",
                ),  # pymongo.IndexModel instance
            ]
  10. Upsert documents

    main

    Use the .upsert() method to insert a document if no documents match the search criteria. When using upsert, you can provide an on_insert parameter to define the document to be created if the update results in an insertion.

    await Product.find_one(Product.name == "Tony's").upsert(
        Set({Product.price: 3.33}), 
        on_insert=Product(name="Tony's", price=3.33, category=chocolate)
    )
  11. Perform simple aggregations with Beanie helper methods

    main

    Beanie provides high-level helper methods for common aggregation tasks like calculating averages. You can run these aggregations on a filtered subset of documents using .find() or over the entire collection by calling the method directly on the Document class.

    # With a search (filtered subset):
    avg_price = await Product.find(
        Product.category.name == "Chocolate"
    ).avg(Product.price)
    
    # Over the whole collection:
    avg_price = await Product.avg(Product.price)